5
5
using System . Diagnostics . CodeAnalysis ;
6
6
using System . Globalization ;
7
7
using System . IO ;
8
+ using System . Linq ;
8
9
using System . Net ;
9
10
using System . Runtime . CompilerServices ;
10
11
using System . Runtime . ExceptionServices ;
@@ -1727,7 +1728,7 @@ public byte[] ReadAllBytes(string path)
1727
1728
using ( var stream = OpenRead ( path ) )
1728
1729
{
1729
1730
var buffer = new byte [ stream . Length ] ;
1730
- _ = stream . Read ( buffer , 0 , buffer . Length ) ;
1731
+ stream . ReadExactly ( buffer , 0 , buffer . Length ) ;
1731
1732
return buffer ;
1732
1733
}
1733
1734
}
@@ -1760,23 +1761,7 @@ public string[] ReadAllLines(string path)
1760
1761
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
1761
1762
public string [ ] ReadAllLines ( string path , Encoding encoding )
1762
1763
{
1763
- /*
1764
- * We use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size
1765
- * for the SftpFileStream. We may want to revisit this later.
1766
- */
1767
-
1768
- var lines = new List < string > ( ) ;
1769
-
1770
- using ( var stream = new StreamReader ( OpenRead ( path ) , encoding ) )
1771
- {
1772
- string ? line ;
1773
- while ( ( line = stream . ReadLine ( ) ) != null )
1774
- {
1775
- lines . Add ( line ) ;
1776
- }
1777
- }
1778
-
1779
- return lines . ToArray ( ) ;
1764
+ return ReadLines ( path , encoding ) . ToArray ( ) ;
1780
1765
}
1781
1766
1782
1767
/// <summary>
@@ -1807,15 +1792,8 @@ public string ReadAllText(string path)
1807
1792
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
1808
1793
public string ReadAllText ( string path , Encoding encoding )
1809
1794
{
1810
- /*
1811
- * We use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size
1812
- * for the SftpFileStream. We may want to revisit this later.
1813
- */
1814
-
1815
- using ( var stream = new StreamReader ( OpenRead ( path ) , encoding ) )
1816
- {
1817
- return stream . ReadToEnd ( ) ;
1818
- }
1795
+ using var sr = new StreamReader ( OpenRead ( path ) , encoding ) ;
1796
+ return sr . ReadToEnd ( ) ;
1819
1797
}
1820
1798
1821
1799
/// <summary>
@@ -1825,12 +1803,16 @@ public string ReadAllText(string path, Encoding encoding)
1825
1803
/// <returns>
1826
1804
/// The lines of the file.
1827
1805
/// </returns>
1828
- /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
1829
- /// <exception cref="SshConnectionException">Client is not connected.</exception>
1830
- /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
1806
+ /// <remarks>
1807
+ /// The lines are enumerated lazily. The opening of the file and any resulting exceptions occur
1808
+ /// upon enumeration.
1809
+ /// </remarks>
1810
+ /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. Thrown eagerly.</exception>
1811
+ /// <exception cref="SshConnectionException">Client is not connected upon enumeration.</exception>
1812
+ /// <exception cref="ObjectDisposedException">The return value is enumerated after the client is disposed.</exception>
1831
1813
public IEnumerable < string > ReadLines ( string path )
1832
1814
{
1833
- return ReadAllLines ( path ) ;
1815
+ return ReadLines ( path , Encoding . UTF8 ) ;
1834
1816
}
1835
1817
1836
1818
/// <summary>
@@ -1841,12 +1823,36 @@ public IEnumerable<string> ReadLines(string path)
1841
1823
/// <returns>
1842
1824
/// The lines of the file.
1843
1825
/// </returns>
1844
- /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
1845
- /// <exception cref="SshConnectionException">Client is not connected.</exception>
1846
- /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
1826
+ /// <remarks>
1827
+ /// The lines are enumerated lazily. The opening of the file and any resulting exceptions occur
1828
+ /// upon enumeration.
1829
+ /// </remarks>
1830
+ /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. Thrown eagerly.</exception>
1831
+ /// <exception cref="SshConnectionException">Client is not connected upon enumeration.</exception>
1832
+ /// <exception cref="ObjectDisposedException">The return value is enumerated after the client is disposed.</exception>
1847
1833
public IEnumerable < string > ReadLines ( string path , Encoding encoding )
1848
1834
{
1849
- return ReadAllLines ( path , encoding ) ;
1835
+ // We allow this usage exception to throw eagerly...
1836
+ ThrowHelper . ThrowIfNull ( path ) ;
1837
+
1838
+ // ... but other exceptions will throw lazily i.e. inside the state machine created
1839
+ // by yield. We could choose to open the file eagerly as well in order to throw
1840
+ // file-related exceptions eagerly (matching what File.ReadLines does), but this
1841
+ // complicates double enumeration, and introduces the problem that File.ReadLines
1842
+ // has whereby the file is not closed if the return value is not enumerated.
1843
+ return Enumerate ( ) ;
1844
+
1845
+ IEnumerable < string > Enumerate ( )
1846
+ {
1847
+ using var sr = new StreamReader ( OpenRead ( path ) , encoding ) ;
1848
+
1849
+ string ? line ;
1850
+
1851
+ while ( ( line = sr . ReadLine ( ) ) != null )
1852
+ {
1853
+ yield return line ;
1854
+ }
1855
+ }
1850
1856
}
1851
1857
1852
1858
/// <summary>
0 commit comments