C# 如何读取大文件并按“拆分”\r\n“;

C# 如何读取大文件并按“拆分”\r\n“;,c#,.net,C#,.net,我有一个大于200MB的大文件。该文件是来自外部方的CSV文件,但遗憾的是,我不能逐行读取该文件,因为\r\n用于定义新行 目前,我正在使用这种方法阅读所有行: var file = File.ReadAllText(filePath, Encoding.Default); var lines = Regex.Split(file, @"\r\n"); for (int i = 0; i < lines.Length; i++) { string line = lines[i];

我有一个大于200MB的大文件。该文件是来自外部方的CSV文件,但遗憾的是,我不能逐行读取该文件,因为
\r\n
用于定义新行

目前,我正在使用这种方法阅读所有行:

var file = File.ReadAllText(filePath, Encoding.Default);
var lines = Regex.Split(file, @"\r\n");

for (int i = 0; i < lines.Length; i++)
{
    string line = lines[i];
    ...
}
您可以使用它返回
IEnumerable
,而不是将整个文件加载到内存中

foreach(var line in File.ReadLines(@filePath, Encoding.Default)
                        .Where(l => !String.IsNullOrEmpty(l)))
{
}
使用它会很容易

using (StreamReader sr = new StreamReader(path)) 
 {
      foreach(string line = GetLine(sr)) 
      {
           //
      }
 }


    IEnumerable<string> GetLine(StreamReader sr)
    {
        while (!sr.EndOfStream)
            yield return new string(GetLineChars(sr).ToArray());
    }

    IEnumerable<char> GetLineChars(StreamReader sr)
    {
        if (sr.EndOfStream)
            yield break;
        var c1 = sr.Read();
        if (c1 == '\\')
        {
            var c2 = sr.Read();
            if (c2 == 'r')
            {
                var c3 = sr.Read();
                if (c3 == '\\')
                {
                    var c4 = sr.Read();
                    if (c4 == 'n')
                    {
                        yield break;
                    }
                    else
                    {
                        yield return (char)c1;
                        yield return (char)c2;
                        yield return (char)c3;
                        yield return (char)c4;
                    }
                }
                else
                {
                    yield return (char)c1;
                    yield return (char)c2;
                    yield return (char)c3;
                }
            }
            else
            {
                yield return (char)c1;
                yield return (char)c2;
            }
        }
        else
            yield return (char)c1;
    }
使用(StreamReader sr=新的StreamReader(路径))
{
foreach(字符串行=GetLine(sr))
{
//
}
}
IEnumerable GetLine(StreamReader sr)
{
而(!sr.EndOfStream)
返回新字符串(GetLineChars(sr).ToArray());
}
IEnumerable GetLineChars(StreamReader sr)
{
if(sr.EndOfStream)
屈服断裂;
var c1=sr.Read();
如果(c1='\\')
{
var c2=sr.Read();
如果(c2=='r')
{
var c3=sr.Read();
如果(c3=='\\')
{
var c4=sr.Read();
如果(c4='n')
{
屈服断裂;
}
其他的
{
收益率(char)c1;
收益率(char)c2;
收益率(char)c3;
产率返回(半焦)c4;
}
}
其他的
{
收益率(char)c1;
收益率(char)c2;
收益率(char)c3;
}
}
其他的
{
收益率(char)c1;
收益率(char)c2;
}
}
其他的
收益率(char)c1;
}

使用StreamReader逐行读取文件:

using (StreamReader sr = new StreamReader(filePath))
{
  while (true)
  {
    string line = sr.ReadLine();
    if (line == null)
      break;
  }
}
怎么样

        StreamReader sr = new StreamReader(path);
        while (!sr.EndOfStream)
        {
                string line = sr.ReadLine();
        }
使用流读取器方法意味着整个文件不会加载到内存中。

这是我的午休时间:)

foreach(var line in File.ReadLines(@filePath, Encoding.Default)
                        .Where(l => !String.IsNullOrEmpty(l)))
{
}
MAXREAD
设置为内存中所需的数据量,例如使用
foreach
,因为我正在使用
yield return
。使用代码的风险由您自己承担,我已经在较小的数据集上尝试过:)

您的用法可能类似于:

foreach (var row in StreamReader(FileName).SplitByChar(new char[] {'\r','\n'}))
{
  // Do something awesome! :)
}    
扩展方法如下:

public static class FileStreamExtensions
{
    public static IEnumerable<string> SplitByChar(this StreamReader stream, char[] splitter)
    {
        int MAXREAD = 1024 * 1024;

        var chars = new List<char>(MAXREAD);

        var bytes = new char[MAXREAD];
        var lastStop = 0;
        var read = 0;

        while (!stream.EndOfStream)
        {
            read = stream.Read(bytes, 0, MAXREAD);
            lastStop = 0;

            for (int i = 0; i < read; i++)
            {
                if (bytes[i] == splitter[0])
                {
                    var assume = true;
                    for (int p = 1; p < splitter.Length; p++)
                    {
                        assume &= splitter[p] == bytes[i + p];
                    }

                    if (assume)
                    {
                        chars.AddRange(bytes.Skip(lastStop).Take(i - lastStop));

                        var res = new String(chars.ToArray());
                        chars.Clear();
                        yield return res;

                        i += splitter.Length - 1;
                        lastStop = i + 1;
                    }
                }
            }
            chars.AddRange(bytes.Skip(lastStop));
        }

        chars.AddRange(bytes.Skip(lastStop).Take(read - lastStop));
        yield return new String(chars.ToArray());
    }
}
公共静态类FileStreamExtensions
{
公共静态IEnumerable SplitByChar(此StreamReader流,char[]拆分器)
{
int MAXREAD=1024*1024;
var chars=新列表(MAXREAD);
var bytes=新字符[MAXREAD];
var lastStop=0;
var read=0;
而(!stream.EndOfStream)
{
read=stream.read(字节,0,MAXREAD);
lastStop=0;
for(int i=0;i
仅检查空值。我们可以在中间有空行。@ DennisMadsen可以跳过空行。它不是关于空行的,它是关于输入格式中的行不是由文件中的新行结束的,而是首先在“\r\n”被看到时。@丹尼斯马森,我不能理解您。代码>\r\n实际上是指新行。你能把你的几行发到像pastebin这样的地方吗。试试这个(
var chars=Environment.NewLine.ToCharArray();
)@L.B他所在的环境可能不是windows,据我所知,重置Environment.NewLine的唯一方法是使用反射。你知道更好的方法吗?@flindeberg不需要重新设置NewLine。File.ReadLines将正确读取它,即使换行符仅为
\r
我明白了,那么看看这个线程,我将尝试diEmAll的方法。。。正如许多人以前指出的那样,
\r\n
是windows环境的默认换行符。您使用的不是windows吗?@DennisMadsen试图回答您的问题,但您的要求很奇怪:)+1用于回答问题。不知道为什么不被接受。也许是因为它不太通用?(我来这里是为了寻找一种将regex find/replace应用于大型文本文件的有效方法,因此这似乎对我的帮助并不比ReadAllText更大。)