[英]FileStream StreamReader problem in C#
我正在測試類FileStream和StreamReader如何工作。 通過控制台應用程序。 我正在嘗試進入文件並讀取行並在控制台上打印它們。
我已經能夠使用while循環來完成它,但我想嘗試使用foreach循環。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace testing
{
public class Program
{
public static void Main(string[] args)
{
string file = @"C:\Temp\New Folder\New Text Document.txt";
using(FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
using(StreamReader sr = new StreamReader(fs))
{
foreach(string line in file)
{
Console.WriteLine(line);
}
}
}
}
}
}
我不斷得到的錯誤是:無法將'char'類型轉換為'string'
while循環確實有效,如下所示:
while((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
我可能忽略了一些非常基本的東西,但我看不到它。
如果要通過foreach(以可重用的方式)逐行讀取文件,請考慮以下迭代器塊:
public static IEnumerable<string> ReadLines(string path)
{
using (StreamReader reader = File.OpenText(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
請注意,這是懶惰的評估 - 沒有與File.ReadAllLines()
關聯的緩沖。 foreach
語法將確保迭代器是Dispose()
d,即使是異常,關閉文件:
foreach(string line in ReadLines(file))
{
Console.WriteLine(line);
}
(這個位只是為了興趣...)
這種抽象的另一個優點是它可以很好地與LINQ一起使用 - 即使用這種方法很容易進行轉換/過濾等:
DateTime minDate = new DateTime(2000,1,1);
var query = from line in ReadLines(file)
let tokens = line.Split('\t')
let person = new
{
Forname = tokens[0],
Surname = tokens[1],
DoB = DateTime.Parse(tokens[2])
}
where person.DoB >= minDate
select person;
foreach (var person in query)
{
Console.WriteLine("{0}, {1}: born {2}",
person.Surname, person.Forname, person.DoB);
}
而且,所有人都懶洋洋地評估(沒有緩沖)。
要讀取New Text Document.txt中的所有行:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace testing
{
public class Program
{
public static void Main(string[] args)
{
string file = @"C:\Temp\New Folder\New Text Document.txt";
using(FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
using(StreamReader sr = new StreamReader(fs))
{
while(!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
}
}
}
}
}
我的MiscUtil項目中有一個LineReader
類。 它比這里給出的解決方案略勝一籌,主要是根據你構建它的方式:
該類“擁有”它使用的任何資源,並適當地關閉它們。 但是,如果不實現IDisposable
本身,它就IDisposable
。 這就是為什么它需要Func<Stream>
和Func<TextReader>
代替流或讀取器直接 - 它需要能夠推遲開放直到它需要它。 它是迭代器本身(由foreach
循環自動處理),它關閉資源。
正如Marc所指出的,這在LINQ中非常有效。 我想給出的一個例子是:
var errors = from file in Directory.GetFiles(logDirectory, "*.log")
from line in new LineReader(file)
select new LogEntry(line) into entry
where entry.Severity == Severity.Error
select entry;
這將從一大堆日志文件中流出所有錯誤,隨着時間的推移打開和關閉。 結合Push LINQ,你可以做各種好東西:)
這不是一個特別“棘手”的課程,但它真的很方便。 這里是完整的源代碼,為方便起見,如果您不想下載MiscUtil。 源代碼的許可證在這里 。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace MiscUtil.IO
{
/// <summary>
/// Reads a data source line by line. The source can be a file, a stream,
/// or a text reader. In any case, the source is only opened when the
/// enumerator is fetched, and is closed when the iterator is disposed.
/// </summary>
public sealed class LineReader : IEnumerable<string>
{
/// <summary>
/// Means of creating a TextReader to read from.
/// </summary>
readonly Func<TextReader> dataSource;
/// <summary>
/// Creates a LineReader from a stream source. The delegate is only
/// called when the enumerator is fetched. UTF-8 is used to decode
/// the stream into text.
/// </summary>
/// <param name="streamSource">Data source</param>
public LineReader(Func<Stream> streamSource)
: this(streamSource, Encoding.UTF8)
{
}
/// <summary>
/// Creates a LineReader from a stream source. The delegate is only
/// called when the enumerator is fetched.
/// </summary>
/// <param name="streamSource">Data source</param>
/// <param name="encoding">Encoding to use to decode the stream
/// into text</param>
public LineReader(Func<Stream> streamSource, Encoding encoding)
: this(() => new StreamReader(streamSource(), encoding))
{
}
/// <summary>
/// Creates a LineReader from a filename. The file is only opened
/// (or even checked for existence) when the enumerator is fetched.
/// UTF8 is used to decode the file into text.
/// </summary>
/// <param name="filename">File to read from</param>
public LineReader(string filename)
: this(filename, Encoding.UTF8)
{
}
/// <summary>
/// Creates a LineReader from a filename. The file is only opened
/// (or even checked for existence) when the enumerator is fetched.
/// </summary>
/// <param name="filename">File to read from</param>
/// <param name="encoding">Encoding to use to decode the file
/// into text</param>
public LineReader(string filename, Encoding encoding)
: this(() => new StreamReader(filename, encoding))
{
}
/// <summary>
/// Creates a LineReader from a TextReader source. The delegate
/// is only called when the enumerator is fetched
/// </summary>
/// <param name="dataSource">Data source</param>
public LineReader(Func<TextReader> dataSource)
{
this.dataSource = dataSource;
}
/// <summary>
/// Enumerates the data source line by line.
/// </summary>
public IEnumerator<string> GetEnumerator()
{
using (TextReader reader = dataSource())
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
/// <summary>
/// Enumerates the data source line by line.
/// </summary>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
問題在於:
foreach(string line in file)
{
Console.WriteLine(line);
}
因為“文件”是字符串,而字符串實現IEnumerable。 但是這個枚舉器返回“char”並且“char”不能被隱含地轉換為字符串。
你應該使用while循環。
以下稍微優雅一點......
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
using (var streamReader = new StreamReader(fileStream))
{
while (!streamReader.EndOfStream)
{
yield return reader.ReadLine();
}
}
}
看起來像我的作業;)
你正在迭代文件名(一個字符串)本身,它一次給你一個字符。 只需使用正確使用sr.ReadLine()的while方法。
您可以簡單地使用File.ReadAllLines
,而不是使用StreamReader
,然后嘗試在String file
變量中查找行。
string[] lines = File.ReadAllLines(file);
foreach(string line in lines)
Console.WriteLine(line);
您正在枚舉一個字符串,當您這樣做時,您當時會使用一個字符串。
你確定這是你想要的嗎?
foreach(string line in file)
迭代文件中每一行的簡單(非內存效率)方法是
foreach (string line in File.ReadAllLines(file))
{
..
}
我認為你想要這樣的東西:
using ( FileStream fileStream = new FileStream( file, FileMode.Open, FileAccess.Read ) )
{
using ( StreamReader streamReader = new StreamReader( fileStream ) )
{
string line = "";
while ( null != ( line = streamReader.ReadLine() ) )
{
Console.WriteLine( line );
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.