Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 读取和剪切文件的有效方法_C#_.net_File Io_Performance - Fatal编程技术网

C# 读取和剪切文件的有效方法

C# 读取和剪切文件的有效方法,c#,.net,file-io,performance,C#,.net,File Io,Performance,我需要做的是,我有几个文件(txt)约2GB的每个。我需要剪切DOS文件,比如说每当出现“%%XGF NEW_SET”标记时,我需要创建新文件并存储它。我认为这个标记大约每隔40-50行出现一次。每行大约有4-20个字符。 因此,我需要将大文件切割成数千个小文件,然后在以后处理它们。我想到了这样一个示例代码 DirectoryInfo di = new DirectoryInfo(ConfigurationManager.AppSettings["BilixFilesDir"])

我需要做的是,我有几个文件(txt)约2GB的每个。我需要剪切DOS文件,比如说每当出现“%%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;
                }
            }
        }
    }

所以我的样品看起来像那样,但我需要高效率。有什么办法可以改进我的解决方案吗?谢谢

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


就我个人而言,我可能会做得稍有不同——让一个读者和一个作者一直处于打开状态,并写下你读到的每一行,除非是“剪切”行,在这种情况下,你只需关闭现有的作者,然后开始新的一行。不过,我并不特别希望在效率上有什么不同。

我会创建一个输出文件流,直到下一个对象出现时才写入其中,从而完全消除对StringBuilder的需求。然后切换到新对象上的新文件流。

谢谢所有提示。考虑到这一点,我将我的代码修改为如下内容:

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的看法。所以,当我需要这种高效率时,它是下一个地方。有什么好的提示吗?

在.NET中有许多不同的读取和写入文件的方法。我已经编写了一个基准测试程序,并在我的博客中给出了结果:

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

另一个有趣的结果是,它观察了一些事情,比如读台词。以每个65536字节的块读取数据并将其解析为行。事实证明,在程序中以块的形式读取数据,然后将其解析为行更有效。我的下载中有一些如何做到这一点的例子

如果你能下载并试用它,然后在这里报告,或者在我的博客上留言,如果它比StreamReader快的话,我会很高兴的。根据我有限的基准,它的速度要快得多

提高程序性能的另一个方法是创建多个线程,并让每个线程处理一个文件。既然你说你有几个大文件,我就把它分解,这样每个大文件都有一个单独的线程

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


Bob Bryan MCSD

分割线上唯一的东西是
%%XGF NEW\u SET
吗?如果没有,您将丢失其他信息,因为您正在丢弃这一行。您的方法是:从原始文件中打开一个流,在每个分节时写入一个新文件。除了在代码可读性方面的一些小优化和减少对stringbuilder的需要之外,我不知道如何使其更快。我所能想到的就是,在您从不同的驱动器重新登录和写入时,将写操作线程化到工作线程可能会有所帮助。