12

我尝试使用以下代码拆分大约 32GB 的文件,但我得到了memory exception.

请建议我使用C#.

string[] splitFile = File.ReadAllLines(@"E:\\JKS\\ImportGenius\\0.txt");

int cycle = 1;
int splitSize = Convert.ToInt32(txtNoOfLines.Text);
var chunk = splitFile.Take(splitSize);
var rem = splitFile.Skip(splitSize);

while (chunk.Take(1).Count() > 0)
{
    string filename = "file" + cycle.ToString() + ".txt";
    using (StreamWriter sw = new StreamWriter(filename))
    {
        foreach (string line in chunk)
        {
    sw.WriteLine(line);
        }
    }
    chunk = rem.Take(splitSize);
    rem = rem.Skip(splitSize);
    cycle++;
}
4

6 回答 6

20

好吧,首先您需要使用File.ReadLines(假设您使用的是.NET 4),这样它就不会尝试将整个内容读入内存。然后我会继续调用一个方法来将“下一个”吐出很多行到一个新文件:

int splitSize = Convert.ToInt32(txtNoOfLines.Text);
using (var lineIterator = File.ReadLines(...).GetEnumerator())
{
    bool stillGoing = true;
    for (int chunk = 0; stillGoing; chunk++)
    {
        stillGoing = WriteChunk(lineIterator, splitSize, chunk);
    }
}

...

private static bool WriteChunk(IEnumerator<string> lineIterator,
                               int splitSize, int chunk)
{
    using (var writer = File.CreateText("file " + chunk + ".txt"))
    {
        for (int i = 0; i < splitSize; i++)
        {
            if (!lineIterator.MoveNext())
            {
                return false;
            }
            writer.WriteLine(lineIterator.Current);
        }
    }
    return true;
}
于 2012-07-26T12:06:13.390 回答
8

不要立即将所有行读入数组,而是使用StremReader.ReadLine方法,例如:

using (StreamReader sr = new StreamReader(@"E:\\JKS\\ImportGenius\\0.txt")) 
{
    while (sr.Peek() >= 0) 
    {
       var fileLine = sr.ReadLine();
       //do something with line
    }
}
于 2012-07-26T12:03:13.013 回答
4
File.ReadAllLines

这会将整个文件读入内存

要处理大文件,您只需将现在需要的内容读入内存,然后在完成后立即将其丢弃。

更好的选择是File.ReadLines返回一个惰性枚举器,数据仅在您从枚举器获取下一行时才读入内存。如果您避免多次枚举(例如,不要使用Count()),则只会读取文件的一部分。

于 2012-07-26T12:05:11.180 回答
3

File.ReadAllLines不要使用一次读取所有文件,而是File.ReadLines在 foreach 循环中根据需要读取行。

foreach (var line in File.ReadLines(@"E:\\JKS\\ImportGenius\\0.txt"))
{
    // Do something
}

编辑:在不相关的注释中,在字符串前面加上“@”前缀时,您不必转义反斜杠。所以要么写"E:\\JKS\\ImportGenius\\0.txt"or @"E:\JKS\ImportGenius\0.txt", but@"E:\\JKS\\ImportGenius\\0.txt"是多余的。

于 2012-07-26T12:03:51.330 回答
0

这里的问题是您正在将整个文件的内容一次读入内存File.ReadAllLines()。您需要做的是打开一个 FileStreamFile.OpenRead()并读取/写入较小的块。

编辑:实际上对于您的情况 ReadLine 显然更好。查看其他答案。:)

于 2012-07-26T12:02:52.330 回答
0

使用StreamReader读取文件,使用 StreamWriter 写入。

于 2012-07-26T12:03:06.120 回答