我使用巨大的数据文件,有时我只需要知道这些文件中的行数,通常我打开它们,一行一行地读取它们,直到我到达文件的末尾
我在想有没有更聪明的办法
我使用巨大的数据文件,有时我只需要知道这些文件中的行数,通常我打开它们,一行一行地读取它们,直到我到达文件的末尾
我在想有没有更聪明的办法
当前回答
这是我迄今为止发现的最快的版本,大约比readLines快6倍。对于150MB的日志文件,这需要0.35秒,而在使用readLines()时需要2.40秒。只是为了好玩,linux的wc -l命令需要0.15秒。
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
编辑,9年半后:我几乎没有java经验,但无论如何,我试图将这段代码与下面的LineNumberReader解决方案进行基准测试,因为没有人这样做让我感到困扰。似乎对于大文件,我的解决方案更快。虽然它似乎需要几次运行,直到优化器做一个像样的工作。我已经玩了一些代码,并产生了一个新版本,始终是最快的:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
1.3GB文本文件的基准测试结果,y轴以秒为单位。我已经对同一个文件执行了100次运行,并使用System.nanoTime()对每次运行进行了测量。您可以看到countLinesOld有一些异常值,而countLinesNew没有异常值,虽然它只是稍微快一点,但差异在统计上是显著的。LineNumberReader显然更慢。
其他回答
这是我迄今为止发现的最快的版本,大约比readLines快6倍。对于150MB的日志文件,这需要0.35秒,而在使用readLines()时需要2.40秒。只是为了好玩,linux的wc -l命令需要0.15秒。
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
编辑,9年半后:我几乎没有java经验,但无论如何,我试图将这段代码与下面的LineNumberReader解决方案进行基准测试,因为没有人这样做让我感到困扰。似乎对于大文件,我的解决方案更快。虽然它似乎需要几次运行,直到优化器做一个像样的工作。我已经玩了一些代码,并产生了一个新版本,始终是最快的:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
1.3GB文本文件的基准测试结果,y轴以秒为单位。我已经对同一个文件执行了100次运行,并使用System.nanoTime()对每次运行进行了测量。您可以看到countLinesOld有一些异常值,而countLinesNew没有异常值,虽然它只是稍微快一点,但差异在统计上是显著的。LineNumberReader显然更慢。
要知道文件里有多少行,唯一的方法就是数数。当然,你可以从你的数据中创建一个指标,给你一个平均长度的一行,然后得到文件大小,并除以平均长度,但这不会是准确的。
似乎有几种不同的方法可以使用LineNumberReader。
我是这样做的:
int lines = 0;
FileReader input = new FileReader(fileLocation);
LineNumberReader count = new LineNumberReader(input);
String line = count.readLine();
if(count.ready())
{
while(line != null) {
lines = count.getLineNumber();
line = count.readLine();
}
lines+=1;
}
count.close();
System.out.println(lines);
更简单的是,可以使用Java BufferedReader lines()方法返回元素流,然后使用stream count()方法对所有元素进行计数。然后只需在输出中添加1,就可以得到文本文件中的行数。
为例:
FileReader input = new FileReader(fileLocation);
LineNumberReader count = new LineNumberReader(input);
int lines = (int)count.lines().count() + 1;
count.close();
System.out.println(lines);
一个直接的方式使用扫描器
static void lineCounter (String path) throws IOException {
int lineCount = 0, commentsCount = 0;
Scanner input = new Scanner(new File(path));
while (input.hasNextLine()) {
String data = input.nextLine();
if (data.startsWith("//")) commentsCount++;
lineCount++;
}
System.out.println("Line Count: " + lineCount + "\t Comments Count: " + commentsCount);
}
我已经实现了这个问题的另一个解决方案,我发现它在计算行数时更有效:
try
(
FileReader input = new FileReader("input.txt");
LineNumberReader count = new LineNumberReader(input);
)
{
while (count.skip(Long.MAX_VALUE) > 0)
{
// Loop just in case the file is > Long.MAX_VALUE or skip() decides to not read the entire file
}
result = count.getLineNumber() + 1; // +1 because line index starts at 0
}