我正在使用CSVHelper库读取CSV文件。但这不是你想要的
请参阅以下代码
public class Reader
{
public IEnumerable<CSVModel> Read(string file)
{
using var reader = new StreamReader(@"C:\Users\z0042d8s\Desktop\GST invoice\RISK All RISKs_RM - Copy.CSV");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
IEnumerable<CSVModel> records = csv.GetRecords<CSVModel>();
return records;
}
}
上面方法中的CSV.getRecords使用yield返回,并在每一个CSV行被读取后立即返回,而不是等到整个CSV文件被读取后再返回(从CSV流数据)
我有一个consumer类,顾名思义,它使用Read方法返回的数据。
class Consumer
{
public void Consume(IEnumerable<CSVModel> data)
{
foreach(var item in data)
{
//Do whatever you want with the data. I am gonna log it to the console
Console.WriteLine(item);
}
}
下面是调用方
public static void main()
{
var data = new Reader().Read();
new Consumer().Consume();
}
希望我没有失去你。
我面临的问题就在下面
由于上面的数据变量是IEnumerable的,所以它将被惰性加载(换句话说,只要不迭代,它就不会读取CSV文件)。但是,当我调用consumer()方法时,它对数据变量进行迭代,强制读取Read()方法中的CSV文件,using语句中的读取器和CSV对象将被释放,引发ObjectDisported异常。
此外,我不想删除using块之外的reader和csv对象,因为它们应该被处理以防止内存泄漏。
异常消息如下
System.ObjectDisposedException: 'GetRecords<T>() returns an IEnumerable<T>
that yields records. This means that the method isn't actually called until
you try and access the values. e.g. .ToList() Did you create CsvReader inside
a using block and are now trying to access the records outside of that using
block?
而且我知道我可以使用贪婪运算符(.toList())。但我想让懒惰的装入工作。
请建议是否有任何出路。
提前道谢。
您可以将操作作为参数传递给读取器。它稍微改变了方法的思想:
public class Reader
{
public void Read(string file, Action<CSVModel> action)
{
using var reader = new StreamReader(@"C:\Users\z0042d8s\Desktop\GST invoice\RISK All RISKs_RM - Copy.CSV");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
IEnumerable<CSVModel> records = csv.GetRecords<CSVModel>();
foreach(var record in records){
action(record);
}
}
}
class Consumer
{
public void Consume(CSVModel data)
{
//Do whatever you want with the data. I am gonna log it to the console
Console.WriteLine(item);
}
}
public static void Main()
{
var consumer = new Consumer();
new Reader().Read(consumer.Consume); // Pass the action here
}
或者,您可以使整个Reader类都是一次性的:
public class Reader : IDisposable
{
private readonly StreamReader _reader;
private readonly CsvReader _csv;
public Reader(string file)
{
_reader = new StreamReader(file);
_csv = new CsvReader(_reader, CultureInfo.InvariantCulture);
}
public IEnumerable<CSVModel> Read()
{
return csv.GetRecords<CSVModel>();
}
public void Dispose() => Dispose(true);
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_csv.Dispose();
_reader.Dispose();
}
_disposed = true;
}
}
class Consumer
{
public void Consume(IEnumerable<CSVModel> data)
{
foreach(var item in data)
{
//Do whatever you want with the data. I am gonna log it to the console
Console.WriteLine(item);
}
}
}
public static void Main()
{
using var myReader = new Reader("c:\\path.csv");
var consumer = new Consumer().Consume(myReader.Read());
}