在C#中以块的方式读取文本文件的最佳方法

3

我需要读取一个大的文本文件,并在每一行中搜索一个字符串,每一行以换行符分隔,我需要尽量减少I/O和RAM的使用。

我的想法是将文件拆成块,所以我有两种方法:

1)使用类似以下的方法分割FileStream,但这样做会冒着把文本行分割成两半的风险,这可能会使事情变得复杂:

 using (FileStream fsSource = new FileStream("InputFiles\\1.txt", FileMode.Open, FileAccess.Read))
            {
                // Read the source file into a byte array.
                int numBytesToRead = 1024; // Your amount to read at a time
                byte[] bytes = new byte[numBytesToRead];

                int numBytesRead = 0;
                while (numBytesToRead > 0)
                {
                    // Read may return anything from 0 to numBytesToRead.
                    int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);

                    // Break when the end of the file is reached.
                    if (n == 0)
                        break;

                    //done something with the lines here.
                }
            }

2) 创建一个扩展方法,将行列表拆分为更小的行列表,然后在每行中搜索单词,但我不确定这种方法如何影响I/O和RAM!

public static IEnumerable<IEnumerable<TValue>> Chunk<TValue>(this IEnumerable<TValue> values, int chunkSize)
        {
            using (var enumerator = values.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    yield return GetChunk(enumerator, chunkSize).ToList();
                }
            }
        }

        private static IEnumerable<T> GetChunk<T>(IEnumerator<T> enumerator, int chunkSize)
        {
            do
            {
                yield return enumerator.Current;
            } while (--chunkSize > 0 && enumerator.MoveNext());
        }

有没有其他想法或方法可以使用?

提前致谢。

2个回答

4
我认为您过于复杂化了事情。当您需要读取文本文件时,.NET框架有许多可供选择的方法。
如果您需要处理大型文本文件,则最好使用File.ReadLines方法,因为它不会将整个文件加载到内存中,而是允许您逐行处理。
正如您可以从MSDN文档中阅读到的那样:

当您使用ReadLines时,您可以在整个集合被返回之前开始枚举字符串集合;

foreach(string line in File.ReadLines(@"InputFiles\1.txt"))
{
    // Process your line here....
}

我知道 :) 但是每次枚举这个列表都会造成一次I/O开销。 - Metalex
但是你的方法并没有最小化RAM,我很确定I/O在某个地方被缓存了。而且你需要解决一个相当复杂的分割行问题。因此,也许你需要测试这两种方法的有效效率。(尽管它更慢,但我会随时选择ReadLines) - Steve
@Metalex -- 你是否遇到了瓶颈或其他问题?如果你的应用程序没有问题,那就不要担心有多少个I/O操作正在进行。 - rory.ap
如果我的文本文件只有一行,但是非常长怎么办? - pkuderov
1
@pkuderov 这取决于您想要对那一长行进行什么操作。您还可以使用BinaryReader.ReadBytes在循环中读取字节块,直到达到文件结尾。 - Steve

0
使用 File.ReadLines 方法,因为它会逐行将内容读入内存中,您可以对每一行进行一些逻辑操作。
foreach(var thisLine in File.ReadLines("path"))
{
    if(thisLine.Contains("Something"))
    {
        // Do something
    }
}

1
但如果你有一个有数百万行的文件,那么这将消耗大量I/O。 - Metalex
@felix-b只是一个打字错误。在链接中我提到了ReadLines。我已经编辑过了。感谢您的提醒。 - CodingYoshi
@Metalex,你可以尝试这种方法,如果发现性能不佳,那么可以使用另一种技术。 - CodingYoshi
@CodingYoshi,我删掉了我的评论 :) - felix-b

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