在C#中读写非常大的文本文件

9

我有一个非常大的文件,大小接近2GB。我试图编写一个处理过程,将该文件读入并在不包括第一行的情况下写出。我只能够一次读取和写入一行,这需要很长时间。虽然我可以打开它,在TextPad中更快地删除第一行并保存,但仍然很慢。

我使用以下代码获取文件中记录的数量:

private long getNumRows(string strFileName)
{
    long lngNumRows = 0;
    string strMsg;

    try
    {
        lngNumRows = 0;
        using (var strReader = File.OpenText(@strFileName))
        {
            while (strReader.ReadLine() != null)
            {
                lngNumRows++;
            }

            strReader.Close();
            strReader.Dispose();
        }
    }
    catch (Exception excExcept)
    {
        strMsg = "The File could not be read: ";
        strMsg += excExcept.Message;
        System.Windows.MessageBox.Show(strMsg);
        //Console.WriteLine("Thee was an error reading the file: ");
        //Console.WriteLine(excExcept.Message);

        //Console.ReadLine();
    }

    return lngNumRows;
}

这只需要几秒钟就可以运行。当我添加下面的代码后,它需要很长时间才能运行。我做错了什么吗?为什么写入操作会花费这么多时间?您有任何关于如何使其更快的想法吗?
private void ProcessTextFiles(string strFileName)
{
    string strDataLine;
    string strFullOutputFileName;
    string strSubFileName;
    int intPos;
    long lngTotalRows = 0;
    long lngCurrNumRows = 0;
    long lngModNumber = 0;
    double dblProgress = 0;
    double dblProgressPct = 0;
    string strPrgFileName = "";
    string strOutName = "";
    string strMsg;
    long lngFileNumRows;

    try
    {
       using (StreamReader srStreamRdr = new StreamReader(strFileName))
        {
            while ((strDataLine = srStreamRdr.ReadLine()) != null)
            {
                lngCurrNumRows++;

                if (lngCurrNumRows > 1)
                {
                    WriteDataRow(strDataLine, strFullOutputFileName);
                }
            }

            srStreamRdr.Dispose();
        }
    }
    catch (Exception excExcept)
    {
        strMsg = "The File could not be read: ";
        strMsg += excExcept.Message;
        System.Windows.MessageBox.Show(strMsg);
        //Console.WriteLine("The File could not be read:");
        //Console.WriteLine(excExcept.Message);
    }
}

public void WriteDataRow(string strDataRow, string strFullFileName)
{
    //using (StreamWriter file = new StreamWriter(@strFullFileName, true, Encoding.GetEncoding("iso-8859-1")))
    using (StreamWriter file = new StreamWriter(@strFullFileName, true, System.Text.Encoding.UTF8))
    {
        file.WriteLine(strDataRow);
        file.Close();
    }
}

6
每写一行要打开和关闭输出文件并不能帮助。 - Steve
正如Steve所说,前面的例子并没有写入任何行。 - kenny
为什么需要计算行数?你不能一次性计算行数并丢弃第一个吗? - BugFinder
2个回答

10

不确定这样做能改善性能有多少,但是每次想要写入一行时打开和关闭输出文件肯定不是一个好主意。

相反,只需打开两个文件一次,然后直接写入该行。

using (StreamWriter file = new StreamWriter(@strFullFileName, true, System.Text.Encoding.UTF8))
using (StreamReader srStreamRdr = new StreamReader(strFileName))
{
    while ((strDataLine = srStreamRdr.ReadLine()) != null)
    {
        lngCurrNumRows++;

        if (lngCurrNumRows > 1)
           file.WriteLine(strDataRow);
    }
}
您也可以通过在进入 while 循环之前进行空读取来删除对 lngCurrNumRow 的检查。
strDataLine = srStreamRdr.ReadLine();
if(strDataLine != null)
{
    while ((strDataLine = srStreamRdr.ReadLine()) != null)
    {
           file.WriteLine(strDataRow);
    }
}

0

根据您的计算机内存大小,您可以尝试以下方法(我的大文件是“D:\ savegrp.log”,大小为2GB)。当我尝试时,这将使用约6GB的内存。

int counter = File.ReadAllLines(@"D:\savegrp.log").Length;
Console.WriteLine(counter);

确实取决于可用内存大小。

File.WriteAllLines(@"D:\savegrp2.log",File.ReadAllLines(@"D:\savegrp.log").Skip(1));
Console.WriteLine("file saved");

我尝试了File.ReadAllLines,但是我没有足够的内存来处理这个文件。 - Cass
谢谢你,Steve,这个完美地解决了问题。用我的方法要花近一个小时,而用file.WriteLine(strDataRow)只需要几分钟。非常感谢大家的迅速回复! - Cass
你编译成了64位吗?我的文件刚刚超过2GB,我的内存使用量增加到了6GB。 - BugFinder
请注意,Steve的答案更好,因为它占用的内存较少,但是这个易于阅读。 - BugFinder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接