我有一个看起来像这样的csv文件
#DELTA,1#
Risk1,10
Risk2,10
Risk3,10
Risk4,10
Risk5,10
#DELTA,1#
Risk6,10
Risk7,10
Risk8,10
Risk9,10
Risk10,10
等等。这些是非常大的文件(按GB的顺序)。
我想要做的是分批阅读
从第一行到下一个#Delta启动之前的csv文件启动streamreader
---Batch 1---
#DELTA,1
Risk1,10
Risk2,10
Risk3,10
Risk4,10
Risk5,10
--Batch 2-----
#DELTA,1
Risk6,10
Risk7,10
Risk8,10
Risk9,10
Risk10,10
----------------------
一旦我得到一个批处理,就把这个子集放进去处理,然后回来重新开始准备另一个批处理,依此类推,直到文件结束。
我已经尝试过制作LINQ了,但是由于我对LINQ的了解,我并没有走得太远。
基本上总的来说,它必须根据我的流中的模式分批流式传输数据..也许我的脑细胞死了或者晚上可能已经太晚了。 真的很适合任何人的帮助
答案 0 :(得分:3)
最简单的方法是TextReader和ReadLine()。
对于定位,我只是在处理批次之间打开Reader。如果这不是一个选项,保存(流)位置并稍后恢复。
使用StreamReader,如果必须关闭文件,则必须保留lineCount并再次从头开始读取和跳过。不太吸引人。
答案 1 :(得分:2)
在Codeplex上至少有一个工具可以在这里使用:KBCsv
答案 2 :(得分:2)
这可能是一种有用的方法。如果您编写一个返回IEnumerable的方法,那么您可以使用yield return
来允许调用者在方法继续之前执行处理。所以,例如,如果你在下面编写像ReadBatches这样的方法......
static IEnumerable<IEnumerable<string>> ReadBatches(string fileName)
{
var file = File.OpenText(fileName);
var batchItems = new List<string>();
while (!file.EndOfStream)
{
// clear the batch list
batchItems.Clear();
// read file in batches of 3
// your logic on splitting batches might differ
for (int i = 0; i < 3; i++)
{
if (file.EndOfStream)
break;
batchItems.Add(file.ReadLine());
}
// this allows the caller to perform processing, and only
// returns back here when they pull on the next item in the
// IEnumerable
yield return batchItems;
}
file.Close();
}
...然后你可以像这样调用这个方法......
static void Main(string[] args)
{
foreach (IEnumerable<string> batch in ReadBatches("data.txt"))
{
Console.WriteLine("*** Processing Batch ***");
foreach (var item in batch)
{
Console.WriteLine(item);
}
}
}
...并且使用看起来像这样的data.txt ......
Row1
Row2
Row3
Row4
Row5
Row6
Row7
...然后你在控制台上看到了这个...
*** Processing Batch ***
Row1
Row2
Row3
*** Processing Batch ***
Row4
Row5
Row6
*** Processing Batch ***
Row7
Press any key to continue . . .
您的方法ReadBatches是一个迭代器块。编译器构建一个状态机,允许执行返回此方法。它允许您编写方法ReadBatches,就好像执行的线程跳回到调用者然后再返回以获得下一批。这不是真正发生的事情(编译器在这里给人留下了深刻的印象),但它是一种编写流式API的非常强大的方法。
我没有处理你的批处理逻辑(我的逻辑只是简单地将3行文件一起批处理)但希望这会给你这个想法。
有关收益率回报的更多信息: http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
关于收益率的热门SO问题在这里: https://stackoverflow.com/tags/yield-return/hot
答案 3 :(得分:2)
假设您可以一次将每个批处理保留在内存中,并且可以始终保持StreamReader
打开,您可能希望编写如下内容:
public static void ProcessBatches(TextReader reader,
Func<string, bool> delimiterDetector,
Action<List<string>> batchAction)
{
string line;
List<string> batch = new List<string>();
while ((line = reader.ReadLine()) != null)
{
if (delimiterDetector(line))
{
batchAction(batch);
batch = new List<string>();
}
}
batchAction(batch);
}
这假设处理批次时不需要分隔符。
然后你会这样称呼它:
using (TextReader reader = File.OpenText("foo.csv"))
{
ProcessBatch(reader, line => line == "# DELTA,1", BatchAction);
}
...
private static void BatchAction(List<string> batch)
{
...
}
答案 4 :(得分:1)
内存映射文件非常适合读取非常大的文件部分,而.NET 4.0现在有managed support for them,因此您不必直接使用Windows API。
答案 5 :(得分:0)
我终于设法解决了。感谢大家的投入。我采用了Enumerable集合并进行了2次循环。 循环1: - 获取所有START OF BATCH(#)的索引在这种情况下+最后一行的索引 循环2: - 取出块并跳过已经拍摄的块。
我计划增强它以使用Observable Collection并在批量完成后调用加载调用然后继续
这是最终的代码,以防它可能有用(或有人可以查看它并建议改进)
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Linq;
namespace LinqToText
{
class Program
{
static void Main(string[] args)
{
var csvLines = new List<string>();
var contextIndexes = new List<int>();
int counter = 0;
var instream = FastReadCsvFile(@"D:\Data\Mock\mock_data.csv");
foreach (var str in instream)
{
if(str.Contains("#"))
{
contextIndexes.Add(counter);
}
counter++;
}
contextIndexes.Add(instream.Count());
foreach (var indexes in contextIndexes)
{
Console.WriteLine(indexes);
}
int[] ixpos = contextIndexes.ToArray();
for(int i = 0 ;i< ixpos.Length-1;i++)
{
int strtPos = ixpos[i];
int endPos = ixpos[i+1];
var batch = instream.Skip(strtPos).Take(endPos - strtPos);
foreach (var dt in batch)
{
Console.WriteLine(dt);
}
}
Console.WriteLine("End Of Processing");
Console.Read();
}
private static IEnumerable<string> FastReadCsvFile(string file)
{
using (var reader = new StreamReader(file, Encoding.Default))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
}
}
答案 6 :(得分:0)
以下是基于KBCsv的实现:
using (var csvReader = new CsvReader(@"D:\Data\Mock\mock_data.csv"))
{
while (csvReader.HasMoreRecords)
{
var record = csvReader.ReadDataRecord();
if (record[0].StartsWith("#"))
{
if (csvReader.RecordCount > 0)
{
EndBatch();
}
BeginBatch();
}
else
{
ProcessRecord(record);
}
}
}
private void BeginBatch()
{
Console.WriteLine("Beginning batch");
}
private void EndBatch()
{
Console.WriteLine("Ending batch");
}
private void ProcessRecord(DataRecord record)
{
Console.WriteLine("Processing record: {0}", record);
}
答案 7 :(得分:0)
所以在Jon Skeet的帮助之后的最终答案是(对某些人有用)。
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace LinqToText
{
class Program
{
static void Main(string[] args)
{
using (TextReader reader = File.OpenText(@"D:\Data\Mock\mock_data.csv"))
{
ProcessBatches(reader, line => line.Contains("#"), BatchAction);
}
Console.WriteLine("End Of Processing");
Console.Read();
}
public static void ProcessBatches(TextReader reader, Func<string, bool> delimiterDetector,Action<List<string>> batchAction)
{
string line;
var batch = new List<string>();
var counter = 0;
while ((line = reader.ReadLine()) != null)
{
if (delimiterDetector(line) && counter !=0)
{
batchAction(batch);
batch = new List<string>();
}
batch.Add(line);
counter++;
}
batchAction(batch);
}
private static void BatchAction(List<string> batch)
{
Console.WriteLine("Processing a single batch...................");
foreach (var str in batch)
{
Console.WriteLine(str);
}
Console.WriteLine("End of single batch processing...................");
Thread.Sleep(1000);
}
}
}
结果是
Processing a single batch...................
#ROW1,1,0,CNO,CURVE CNO #0,CNO6M,Tenor set CNO #0,ON|TN|1D|1W|1M|2M|3M|1Y|2Y|3Y|
4Y|5Y|6Y|7Y|8Y|9Y|10Y|11Y|12Y|13Y|14Y|15Y|16Y|17Y|18Y|19Y|20Y|21Y|
Risk1,10
Risk2,10
Risk3,10
Risk4,10
Risk5,10
End of single batch processing...................
Processing a single batch...................
#ROW2,1,0,CNO,CURVE CNO #0,CNO6M,Tenor set CNO #0,ON|TN|1D|1W|1M|2M|3M|1Y|2Y|3Y|
4Y|5Y|6Y|7Y|8Y|9Y|10Y|11Y|12Y|13Y|14Y|15Y|16Y|17Y|18Y|19Y|20Y|21Y|
Risk6,10
Risk7,10
Risk8,10
Risk9,10
Risk10,10
End of single batch processing...................
Processing a single batch...................
#ROW3,1,0,CNO,CURVE CNO #0,CNO6M,Tenor set CNO #0,ON|TN|1D|1W|1M|2M|3M|1Y|2Y|3Y|
4Y|5Y|6Y|7Y|8Y|9Y|10Y|11Y|12Y|13Y|14Y|15Y|16Y|17Y|18Y|19Y|20Y|21Y|
Risk11,10
Risk12,10
Risk13,10
Risk14,10
Risk15,10
End of single batch processing...................
Processing a single batch...................
#ROW4,1,0,CNO,CURVE CNO #0,CNO6M,Tenor set CNO #0,ON|TN|1D|1W|1M|2M|3M|1Y|2Y|3Y|
4Y|5Y|6Y|7Y|8Y|9Y|10Y|11Y|12Y|13Y|14Y|15Y|16Y|17Y|18Y|19Y|20Y|21Y|
Risk16,10
Risk17,10
Risk18,10
Risk19,10
Risk20,10
End of single batch processing...................
End Of Processing
感谢大家的帮助和Jon给出的最终解决方案。