假设你有一个文本文件 - 确定该文件中文本行数的最快和/或最有效的内存方法是什么?
是否只是逐个字符地扫描它并寻找换行符?
答案 0 :(得分:11)
可能不是最快的,但它将是最多才多艺的......
int lines = 0;
/* if you need to use an encoding other than UTF-8 you way want to try...
new StreamReader("filename.txt", yourEncoding)
... instead of File.OpenText("myFile.txt")
*/
using (var fs = File.OpenText("myFile.txt"))
while (!fs.EndOfStream)
{
fs.ReadLine();
lines++;
}
......这可能会更快......
如果您需要更高的速度,可以尝试Duff's device并检查分支前的10或20个字节
int lines = 0;
var buffer = new byte[32768];
var bufferLen = 1;
using (var fs = File.OpenRead("filename.txt"))
while (bufferLen > 0)
{
bufferLen = fs.Read(buffer, 0, 32768);
for (int i = 0; i < bufferLen; i++)
/* this is only known to work for UTF-8/ASCII other
file types may need to search for different End Of Line
characters */
if (buffer[i] == 10)
lines++;
}
答案 1 :(得分:10)
除非你有一个固定的行长度(就 bytes 而言),你肯定需要读取数据。是否可以避免将所有数据转换为文本将取决于编码。
现在最有效的方法是重新加载 - 手动计算行结尾。但是,最简单的代码将使用TextReader.ReadLine()
。事实上,最简单的方法是使用MiscUtil中的LineReader
类,它将文件名(或其他各种内容)转换为IEnumerable<string>
。然后你可以使用LINQ:
int lines = new LineReader(filename).Count();
(如果你不想抓住整个MiscUtil,你可以从this answer单独获得LineReader
。)
现在这会产生大量的垃圾,反复读入相同的char数组也不会 - 但它一次不会读取多行,所以虽然你会给GC一点压力,但是不会炸毁大文件。它还需要将所有数据解码为文本 - 您可能能够在不执行某些编码的情况下离开。
就个人而言,这是我使用的代码,直到我发现它造成了瓶颈 - 它比手动操作要简单得多。你绝对知道在你目前的情况下,上面的代码会成为瓶颈吗?
与以往一样,不要微观优化,直到你必须...而且你可以在以后很容易地优化它而不改变你的整体设计,所以推迟它不会造成任何伤害。
编辑:要将Matthew的答案转换为适用于任何编码的答案 - 但这将导致解码所有数据的代价,当然,您可能会得到类似下面代码的内容。我假设您仅关心\n
- 而不是\r
,\n
和\r\n
TextReader
通常会处理:
public static int CountLines(string file, Encoding encoding)
{
using (TextReader reader = new StreamReader(file, encoding))
{
return CountLines(reader);
}
}
public static int CountLines(TextReader reader)
{
char[] buffer = new char[32768];
int charsRead;
int count = 0;
while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
{
for (int i = 0; i < charsRead; i++)
{
if (buffer[i] == '\n')
{
count++;
}
}
}
return count;
}
答案 2 :(得分:5)
如果它是固定记录,您可以获取记录的大小,然后将总文件大小除以该数量以获得记录数。如果您只是在寻找估计值,那么我过去所做的只是读取前x行(例如200行)并使用它来得出平均行大小,然后您可以使用它来猜测总数记录(将文件总大小除以平均行大小)。如果您的记录相当统一并且您不需要精确计数,则此方法很有效。我已经在大文件上使用了这个(快速检查以获取文件大小,如果它超过20 MB然后得到估计而不是读取整个文件)。
除此之外,唯一100%准确的方法是使用ReadLine逐行浏览文件。
答案 3 :(得分:3)
我一次读取32kb(或更多),计算内存块中\ r \ n的数量并重复直到完成。
答案 4 :(得分:2)
最简单的:
int lines = File.ReadAllLines(fileName).Length;
这当然会将所有文件读入内存,因此它根本不是内存效率。最有效的内存是将文件作为流读取并查找换行符。这也是最快的,因为它是最小的开销。
没有可以使用的快捷方式。文件不是基于行的,因此没有可以使用的额外信息,另一种方法是您必须阅读并检查文件的每个字节。
答案 5 :(得分:1)
我相信Windows使用两个字符来标记行的结尾(如果我没记错的话,可以使用10H和13H),所以你只需要检查这两行中的每一个字符。
答案 6 :(得分:1)
由于这是一个纯粹的顺序过程,位置之间没有依赖关系,因此如果数据非常庞大,请考虑map / reduce。在C / C ++中,您可以使用OpenMP进行并行操作。每个线程将读取一个块并计算该块中的CRLF。最后,在减少部分,他们将总结他们的个人数量。英特尔线程构建模块为您提供基于C ++模板的并行性构造。我同意这是一个小文件的大锤方法,但从纯粹的性能角度来看,这是最佳的(分而治之)