高效的阅读和剪切文件的方式

时间:2011-02-11 14:42:33

标签: c# .net file-io performance

我需要做的是我有几个文件(txt),每个文件大约2GB。我需要剪切文件让我们说每当'%% XGF NEW_SET'标记出现时我需要创建新文件并存储它。我认为这个标记出现在每40-50行。每条线都有4到20个字符。 因此,我需要将大文件剪切成数千个小文件,然后再处理它们。我想到了这样的示例代码。

        DirectoryInfo di = new DirectoryInfo(ConfigurationManager.AppSettings["BilixFilesDir"]);
        var files = di.GetFiles();
        int count = 0;
        bool hasObject = false;
        StringBuilder sb = new StringBuilder();
        string line = "";
        foreach (var file in files)
        {
            using (StreamReader sr = new StreamReader(file.FullName,Encoding.GetEncoding(1250)))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    //when new file starts
                    if (line.Contains("%%XGF NEW_SET"))
                    {
                        //when new file existed I need to store old one
                        if (hasObject)
                        {
                            File.WriteAllText(string.Format("{0}/{1}-{2}", ConfigurationManager.AppSettings["OutputFilesDir"], count++, file.Name), sb.ToString());
                            sb.Length = 0;
                            sb.Capacity = 0;

                        }
                        //setting exist flag 
                        hasObject = true;
                    }
                    //when there is no new object
                    else
                        //when object exists adding new lines
                        if (hasObject)
                            sb.AppendLine(line);
                }
                //when all work done saving last object
                if (hasObject)
                {
                    File.WriteAllText(string.Format("{0}/{1}-{2}", ConfigurationManager.AppSettings["OutputFilesDir"], count++, file.Name), sb.ToString());
                    sb.Length = 0;
                    sb.Capacity = 0;
                }
            }
        }
    }

所以我的样本看起来像这样,但我需要高效率。我有什么想法可以改进我的解决方案?感谢

4 个答案:

答案 0 :(得分:2)

与目前的代码相比,您需要什么样的效率?

就我个人而言,我可能会略有不同 - 保持读者和作者一直打开,并写下你读过的每一行,除非它是一个“剪切”行,在这种情况下你只需关闭现有的作者和开始一个新的。我不会特别期待那里的效率有所不同。

答案 1 :(得分:1)

我将完全消除对StringBuilder的需求,方法是创建一个输出文件流,直到下一个对象出现为止。然后切换到新对象上的新文件流。

答案 2 :(得分:0)

感谢您的所有提示。在考虑之后,我已经将我的代码修改成这样的东西:

DirectoryInfo di = new DirectoryInfo(ConfigurationManager.AppSettings["BilixFilesDir"]);
//getting all files from dir
var files = di.GetFiles();
int count = 0;
bool hasObject = false;
string line = "";
StreamWriter sw = null;
foreach (var file in files)
{
    using (StreamReader sr = new StreamReader(file.FullName, Encoding.GetEncoding(1250)))
    {
        while ((line = sr.ReadLine()) != null)
        {
            //when new file starts
            if (line.Contains("%%XGF NEW_SET"))
            {
                //when new file existed I need to store old one
                if (hasObject)
                {
                    sw.Close();
                }
                else
                {
                    //creating new file and setting exist flag
                    hasObject = true;
                    sw = new StreamWriter(string.Format("{0}/{1}-{2}", ConfigurationManager.AppSettings["OutputFilesDir"], count++, file.Name));
                    //Bill bill = new Bill();                              
                }
            }
            else
                //when object exists adding new lines
                if (hasObject)
                    sw.WriteLine(line);
        }
        //when all work done saving last object
        if (hasObject)
        {
            sw.Close();
            hasObject = false;
        }
    }
}
sw.Dispose();

你怎么看待这样的事情?

我还需要做的一件事: 我的大文件可以存储不同的文件。所有这些都有不同的标记开始。 假设有20种文件。有时会有相同的标记开始,但在文档中有一些额外的标记,使我能够识别文档类型。我的意思是,例如,2个文档具有相同的标记开始,如“%% XGF NEW_SET”,但后者标记为“BILL_A”,而其他文件没有。我必须为每个剪切文件创建一个文件,其中包含文档中的一些索引和包含该类型的字符串。基本上在保存我的StreamWriter之前,我必须提取所有这些索引以及我对StringBuilder的思考方式。因此,当我需要这种高效率时,它是下一个地方。有什么好的建议吗?

答案 3 :(得分:0)

有许多不同的方法可以在.NET中读取和写出文件。我写了一个基准程序,并在我的博客中提供结果:

http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp

如果您需要性能,我建议使用Windows ReadFile和WriteFile方法。避免使用任何异步方法,因为我的基准测试结果表明使用同步I / O方法可以获得更好的性能 - 至少对于FileStream来说,这是用于读取文件的最快的.NET类。我在C#中编写了一个封装了ReadFile和WriteFile功能使其易于使用。

另一个有趣的结果是,它看起来像阅读线.vs。以65,536字节的块读取数据并将其解析为行。事实证明,以块为单位读取数据然后将其解析为程序内的行更有效。我的下载有一些如何做到这一点的例子。

我很乐意,如果您下载并试用它并在此处报告,或者如果它比StreamReader快,请在我的博客上发表评论。根据我的有限基准,它明显更快。

提高程序性能的另一个想法是创建多个线程并让每个线程处理一个文件。既然你说你有一些大文件,我会把它分解,以便每个大文件都有一个单独的线程。

如果你正在使用字符串做很多工作,那么你肯定应该使用StringBuilder。但是,或许更有效的方法是将数据读入字节数组,然后构建一个字节数组用于输出。如果这不比使用StringBuilder更有效,我会感到惊讶。

Bob Bryan MCSD