C# 非常大的半csv文件-内存不足
我有一个2.6GB的半csv文件需要解析。我所说的半csv是指它的形式(数据,数据2,数据3,…)(更多数据,更多数据2,更多数据3,…)(…)。这意味着新行由“,”组成,而不是换行(这意味着整个文件基本上是一行)C# 非常大的半csv文件-内存不足,c#,csv,out-of-memory,C#,Csv,Out Of Memory,我有一个2.6GB的半csv文件需要解析。我所说的半csv是指它的形式(数据,数据2,数据3,…)(更多数据,更多数据2,更多数据3,…)(…)。这意味着新行由“,”组成,而不是换行(这意味着整个文件基本上是一行) 我的计划是读入该文件并按“,”分开,然后我可以根据需要解析每个元素。显然,C#有“内存不足”的问题,但我不能只拆分文件,因为我不能保证拆分不会错误地拆分数据。有什么办法吗?完全未经测试,字符串必须是“mystring”。不支持字符串中的转义。不支持字符串中的“转义。因此这些无效:“我
我的计划是读入该文件并按“,”分开,然后我可以根据需要解析每个元素。显然,C#有“内存不足”的问题,但我不能只拆分文件,因为我不能保证拆分不会错误地拆分数据。有什么办法吗?完全未经测试,字符串必须是
“mystring”
。不支持字符串中的转义。不支持字符串中的“
转义。因此这些无效:“我的”“引号”
或“我的”“引号”
。文件必须是完美的:结尾没有eof,结尾没有新行,字符串内没有空格,字符串内没有新行。字符串内除了“
(标记字符串结尾的)之外没有任何内容,没有元素太多的行,没有元素太少的行,没有null
处理(从技术上讲,字符串的,
将返回一个空字符串,不会引发错误)。支持转换.ChangeType
支持的所有类型
用法:
using (var fs = new StreamReader("myfile.txt"))
{
foreach (var objs in ParseStream(sr, new Type[] { typeof(int), typeof(double), typeof(string) }, CultureInfo.InvariantCulture))
{
// objs is an object[] where each member is of the type asked
// when ParseStream was called
}
}
代码
公共静态IEnumerable ParseStream(TextReader tr,类型[]类型,IFormatProvider区域性=null)
{
var parts=新列表();
var sb=新的StringBuilder();
State State=State.WaitingForOpenBracket;
长列=-1;
长行=0;
int-read;
而((read=tr.read())!=-1)
{
col++;
char ch=(char)read;
如果(ch='\n')
{
col=0;
行++;
}
其他的
{
col++;
}
开关(状态)
{
案例状态。等待打开括号:
如果(ch!='(')
{
抛出新异常(string.Format(“R:{0},C:{1},char:{2},row,col,ch的行的开头格式错误”);
}
state=state.WaitingForData;
打破
case State.WaitingForData:
案例状态.WaitingForColumnSeptor:
如果(ch==','| | ch==')')
{
添加(sb.ToString());
(某人清楚地);
如果(parts.Count>types.Length)
{
抛出新异常(string.Format(“从R:{0},C:{1}”,行,列开始的部分太多”);
}
如果(ch==')')
{
var parts2=parts.Select((p,ix)=>Convert.ChangeType(p,types[ix],culture??CultureInfo.InvariantCulture)).ToArray();
零件。清除();
屈服返回部分2;
state=state.WaitingForRowSeparator;
}
}
其他的
{
if(state==state.waitingforcolumnseptor)
{
抛出新异常(string.Format(“R:{0},C:{1},char:{2},row,col,ch处格式错误的列分隔符”);
}
如果(ch==“”)
{
如果(某人长度!=0)
{
抛出新异常(string.Format(“R:{0},C:{1},char:{2},row,col,ch处格式错误的字符串”);
}
state=state.WaitingForEndQuotes;
}
其他的
{
某人附加(ch);
}
}
打破
案例状态。WaitingForEndQuotes:
如果(ch==“”)
{
state=state.waitingforcolumnseptor;
}
其他的
{
某人附加(ch);
}
打破
案例状态。WaitingForRowSeparator:
如果(ch!=',')
{
抛出新异常(string.Format(“R:{0},C:{1},char:{2},row,col,ch处格式错误的行分隔符”);
}
state=state.WaitingForOpenBracket;
打破
}
}
if(state!=state.WaitingForRowSeparator)
{
抛出新的异常(string.Format(“R:{0},C:{1},row,col处文件的格式错误的结尾”);
}
}
仅为数字数据,或者可以包含字符串?您需要使用System.IO.BinaryReader。不要“读取”文件"。这就是问题所在。流式处理文件并逐行处理。这也会更快。您无法读取整个文件…由于编码,它将变为5gb…并且您的字符串长度不能超过2gb…然后将有一个
StringBuilder
来构建该字符串。内存太多。现在…如果没有字符串和文件的格式是完美的(在)
和,
和(
)之间没有空格。这个问题相当复杂(我会说需要2/3个小时)…字符串的处理是+1h,带引号转义的字符串的处理是+1h,错误格式的处理是+1h…这个问题可能相当困难。
public static IEnumerable<object[]> ParseStream(TextReader tr, Type[] types, IFormatProvider culture = null)
{
var parts = new List<string>();
var sb = new StringBuilder();
State state = State.WaitingForOpenBracket;
long col = -1;
long row = 0;
int read;
while ((read = tr.Read()) != -1)
{
col++;
char ch = (char)read;
if (ch == '\n')
{
col = 0;
row++;
}
else
{
col++;
}
switch (state)
{
case State.WaitingForOpenBracket:
if (ch != '(')
{
throw new Exception(string.Format("Malformed begin-of-the-row at R: {0}, C: {1}, char: {2}", row, col, ch));
}
state = State.WaitingForData;
break;
case State.WaitingForData:
case State.WaitingForColumnSeparator:
if (ch == ',' || ch == ')')
{
parts.Add(sb.ToString());
sb.Clear();
if (parts.Count > types.Length)
{
throw new Exception(string.Format("Too many parts starting at R: {0}, C: {1}", row, col));
}
if (ch == ')')
{
var parts2 = parts.Select((p, ix) => Convert.ChangeType(p, types[ix], culture ?? CultureInfo.InvariantCulture)).ToArray();
parts.Clear();
yield return parts2;
state = State.WaitingForRowSeparator;
}
}
else
{
if (state == State.WaitingForColumnSeparator)
{
throw new Exception(string.Format("Malformed column separator at R: {0}, C: {1}, char: {2}", row, col, ch));
}
if (ch == '"')
{
if (sb.Length != 0)
{
throw new Exception(string.Format("Malformed string at R: {0}, C: {1}, char: {2}", row, col, ch));
}
state = State.WaitingForEndQuotes;
}
else
{
sb.Append(ch);
}
}
break;
case State.WaitingForEndQuotes:
if (ch == '"')
{
state = State.WaitingForColumnSeparator;
}
else
{
sb.Append(ch);
}
break;
case State.WaitingForRowSeparator:
if (ch != ',')
{
throw new Exception(string.Format("Malformed row separator at R: {0}, C: {1}, char: {2}", row, col, ch));
}
state = State.WaitingForOpenBracket;
break;
}
}
if (state != State.WaitingForRowSeparator)
{
throw new Exception(string.Format("Malformed end-of-file at R: {0}, C: {1}", row, col));
}
}