在看了一会儿的时候,我发现了很多关于如何计算文件中行数的讨论。
例如这三个:
c# how do I count lines in a textfile
Determine the number of lines within a text file
How to count lines fast?
所以,我继续前进并最终使用了我能找到的效率最高(至少是内存方式?)的方法:
private static int countFileLines(string filePath)
{
using (StreamReader r = new StreamReader(filePath))
{
int i = 0;
while (r.ReadLine() != null)
{
i++;
}
return i;
}
}
但是,当文件中的行本身非常长时,这将永远存在。真的没有更快的解决方案吗?
我一直在尝试使用StreamReader.Read()
或StreamReader.Peek()
,但我不能(或者不知道如何)让他们中的任何一个一旦进入下一行'东西'(字符?文字?)。
有什么想法吗?
结论/结果(根据提供的答案运行一些测试后):
我在两个不同的文件上测试了下面的5个方法,我得到了一致的结果,似乎表明普通的StreamReader.ReadLine()
仍然是最快的方法之一...说实话,我总是感到困惑答案中的评论和讨论。
文件#1:
尺寸:3,631 KB
线:56,870
文件#1的秒数结果:
0.02 - > ReadLine方法。
0.04 - >读方法。
0.29 - > ReadByte方法。
0.25 - > Readlines.Count方法。
0.04 - > ReadWithBufferSize方法。
文件#2:
大小:14,499 KB
行:213,424
文件#1的秒数结果:
0.08 - > ReadLine方法。
0.19 - >读方法。
1.15 - > ReadByte方法。
1.02 - > Readlines.Count方法。
0.08 - > ReadWithBufferSize方法。
以下是我根据收到的所有反馈测试的5种方法:
private static int countWithReadLine(string filePath)
{
using (StreamReader r = new StreamReader(filePath))
{
int i = 0;
while (r.ReadLine() != null)
{
i++;
}
return i;
}
}
private static int countWithRead(string filePath)
{
using (StreamReader _reader = new StreamReader(filePath))
{
int c = 0, count = 0;
while ((c = _reader.Read()) != -1)
{
if (c == 10)
{
count++;
}
}
return count;
}
}
private static int countWithReadByte(string filePath)
{
using (Stream s = new FileStream(filePath, FileMode.Open))
{
int i = 0;
int b;
b = s.ReadByte();
while (b >= 0)
{
if (b == 10)
{
i++;
}
b = s.ReadByte();
}
return i;
}
}
private static int countWithReadLinesCount(string filePath)
{
return File.ReadLines(filePath).Count();
}
private static int countWithReadAndBufferSize(string filePath)
{
int bufferSize = 512;
using (Stream s = new FileStream(filePath, FileMode.Open))
{
int i = 0;
byte[] b = new byte[bufferSize];
int n = 0;
n = s.Read(b, 0, bufferSize);
while (n > 0)
{
i += countByteLines(b, n);
n = s.Read(b, 0, bufferSize);
}
return i;
}
}
private static int countByteLines(byte[] b, int n)
{
int i = 0;
for (int j = 0; j < n; j++)
{
if (b[j] == 10)
{
i++;
}
}
return i;
}
答案 0 :(得分:9)
不,不是。点是 - 它实现了字符串,这是不需要的。
要计算它,你最好忽略“string”Part并转到“line”Part。
LINE是一系列以\ r \ n(13,10-CR LF)或其他标记结尾的字节。
只需沿缓冲流中的字节运行,计算行结束标记的出现次数。
答案 1 :(得分:5)
了解如何快速完成此操作的最佳方法是在不使用C / C ++的情况下考虑最快的方法。
在汇编中有一个CPU级操作,它会扫描内存中的字符,因此在汇编时你可以执行以下操作
因此,在C#中,您希望编译器尽可能接近它。
答案 2 :(得分:4)
我尝试了多种方法并测试了它们的性能:
读取单个字节的速度比其他方法慢约50%。其他方法都返回大约相同的时间。您可以尝试创建线程并异步执行此操作,因此在等待读取时,您可以开始处理先前的读取。这对我来说听起来很头疼。
我会选择一个班轮:File.ReadLines(filePath).Count();
它的表现与我测试的其他方法一样。
private static int countFileLines(string filePath)
{
using (StreamReader r = new StreamReader(filePath))
{
int i = 0;
while (r.ReadLine() != null)
{
i++;
}
return i;
}
}
private static int countFileLines2(string filePath)
{
using (Stream s = new FileStream(filePath, FileMode.Open))
{
int i = 0;
int b;
b = s.ReadByte();
while (b >= 0)
{
if (b == 10)
{
i++;
}
b = s.ReadByte();
}
return i + 1;
}
}
private static int countFileLines3(string filePath)
{
using (Stream s = new FileStream(filePath, FileMode.Open))
{
int i = 0;
byte[] b = new byte[bufferSize];
int n = 0;
n = s.Read(b, 0, bufferSize);
while (n > 0)
{
i += countByteLines(b, n);
n = s.Read(b, 0, bufferSize);
}
return i + 1;
}
}
private static int countByteLines(byte[] b, int n)
{
int i = 0;
for (int j = 0; j < n; j++)
{
if (b[j] == 10)
{
i++;
}
}
return i;
}
private static int countFileLines4(string filePath)
{
return File.ReadLines(filePath).Count();
}
答案 3 :(得分:3)
public static int CountLines(Stream stm)
{
StreamReader _reader = new StreamReader(stm);
int c = 0, count = 0;
while ((c = _reader.Read()) != -1)
{
if (c == '\n')
{
count++;
}
}
return count;
}
答案 4 :(得分:3)
是的,在任何实际意义上,阅读这样的行是最快最简单的方法。
这里没有捷径。文件不是基于行的,因此您必须从文件中读取每个字节以确定有多少行。
正如TomTom指出的那样,创建字符串并不是严格需要来计算行数,但是花费的绝大部分时间都是等待从磁盘读取数据。编写更复杂的算法可能会减少执行时间的百分比,并且会大大增加编写和测试代码的时间。
答案 5 :(得分:2)
有许多方法可以读取文件。通常,最快的方式最简单:
using (StreamReader sr = File.OpenText(fileName))
{
string s = String.Empty;
while ((s = sr.ReadLine()) != null)
{
//do what you gotta do here
}
}
This page does a great performance comparison介于几种不同的技术之间,包括使用BufferedReaders,读入StringBuilder对象,以及整个数组。
答案 6 :(得分:0)
StreamReader
通常不是读取文件的最快方法,因为将字节编码为字符的开销很小,因此以字节数组读取文件的速度更快。
由于缓存和其他进程,我得到的结果每次都有点不同,但这是我得到的结果之一(以毫秒为单位)和16 MB文件:
75 ReadLines
82 ReadLine
22 ReadAllBytes
23 Read 32K
21 Read 64K
27 Read 128K
通常File.ReadLines
应该比StreamReader.ReadLine
循环慢一点。
对于较大的文件,File.ReadAllBytes
速度较慢,并且会因巨大的文件而丢失内存异常。
FileStream
的默认缓冲区大小为4K,但在我的机器上64K似乎是最快的。
private static int countWithReadLines(string filePath)
{
int count = 0;
var lines = File.ReadLines(filePath);
foreach (var line in lines) count++;
return count;
}
private static int countWithReadLine(string filePath)
{
int count = 0;
using (var sr = new StreamReader(filePath))
while (sr.ReadLine() != null)
count++;
return count;
}
private static int countWithFileStream(string filePath, int bufferSize = 1024 * 4)
{
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
int count = 0;
byte[] array = new byte[bufferSize];
while (true)
{
int length = fs.Read(array, 0, bufferSize);
for (int i = 0; i < length; i++)
if(array[i] == 10)
count++;
if (length < bufferSize) return count;
}
} // end of using
}
并测试:
var path = "1234567890.txt"; Stopwatch sw; string s = "";
File.WriteAllLines(path, Enumerable.Repeat("1234567890abcd", 1024 * 1024 )); // 16MB (16 bytes per line)
sw = Stopwatch.StartNew(); countWithReadLines(path) ; sw.Stop(); s += sw.ElapsedMilliseconds + " ReadLines \n";
sw = Stopwatch.StartNew(); countWithReadLine(path) ; sw.Stop(); s += sw.ElapsedMilliseconds + " ReadLine \n";
sw = Stopwatch.StartNew(); countWithReadAllBytes(path); sw.Stop(); s += sw.ElapsedMilliseconds + " ReadAllBytes \n";
sw = Stopwatch.StartNew(); countWithFileStream(path, 1024 * 32); sw.Stop(); s += sw.ElapsedMilliseconds + " Read 32K \n";
sw = Stopwatch.StartNew(); countWithFileStream(path, 1024 * 64); sw.Stop(); s += sw.ElapsedMilliseconds + " Read 64K \n";
sw = Stopwatch.StartNew(); countWithFileStream(path, 1024 *128); sw.Stop(); s += sw.ElapsedMilliseconds + " Read 128K \n";
MessageBox.Show(s);