当前位置:  开发笔记 > 编程语言 > 正文

Java中文件中的行数

如何解决《Java中文件中的行数》经验,为你挑选了7个好方法。

我使用大量数据文件,有时我只需要知道这些文件中的行数,通常我打开它们并逐行读取它们直到我到达文件末尾

我想知道是否有更聪明的方法来做到这一点



1> martinus..:

这是迄今为止我发现的最快版本,比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) {
            System.out.println(readChars);
            for (int i=0; i

基准测试结果为1.3GB文本文件,y轴以秒为单位.我用相同的文件执行了100次运行,并测量了每次运行System.nanoTime().您可以看到它countLinesOld有一些异常值,并且countLinesNew没有异常值,虽然它只是快一点,但差异在统计上是显着的.LineNumberReader显然比较慢.

基准情节


当你完成它时,你将关闭那个InputStream,不是吗?
两件事:(1)Java源代码中行终止符的定义是回车符,换行符或回车符后跟换行符.您的解决方案不适用于用作线路终结器的CR.当然,我认为唯一使用CR作为默认行终止符的操作系统是Mac OS X之前的Mac OS.(2)您的解决方案采用字符编码,如US-ASCII或UTF-8.对于诸如UTF-16的编码,行计数可能不准确.
BufferedInputStream应该为你做缓冲,所以我没有看到使用中间byte []数组如何使它更快.你不可能比重复使用readLine()做得更好(因为它将通过API进行优化).
如果缓冲有帮助,因为BufferedInputStream默认缓冲8K.将byte []增加到此大小或更大,您可以删除BufferedInputStream.例如尝试1024*1024字节.
令人敬畏的代码......对于400mb文本文件,它花了一秒钟.非常感谢@martinus

2> 小智..:

我已经实现了另一个问题的解决方案,我发现它在计算行时效率更高:

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
}


我已经投了这个回应,因为似乎没有人对它进行过基准测试

3> DMulligan..:

对于不以换行结尾的多行文件,接受的答案有一个错误.以换行符结尾的单行文件将返回1,但是没有换行符的两行文件也将返回1.以下是修复此问题的已接受解决方案的实现.除了最终阅读之外,endsWithoutNewLine检查对于所有内容都是浪费,但与整体功能相比应该是微不足道的时间.

public int count(String filename) throws IOException {
    InputStream is = new BufferedInputStream(new FileInputStream(filename));
    try {
        byte[] c = new byte[1024];
        int count = 0;
        int readChars = 0;
        boolean endsWithoutNewLine = false;
        while ((readChars = is.read(c)) != -1) {
            for (int i = 0; i < readChars; ++i) {
                if (c[i] == '\n')
                    ++count;
            }
            endsWithoutNewLine = (c[readChars - 1] != '\n');
        }
        if(endsWithoutNewLine) {
            ++count;
        } 
        return count;
    } finally {
        is.close();
    }
}


接得好.不知道为什么你不只是编辑接受的答案并在评论中做一个注释.大多数人都不会读到这么远.
此解决方案不处理回车符(\ r)和回车符后跟换行符(\ r \n)

4> msayag..:

使用java-8,您可以使用流:

try (Stream lines = Files.lines(path, Charset.defaultCharset())) {
  long numOfLines = lines.count();
  ...
}



5> 小智..:

上面的方法count()的答案给了我行错误计数,如果文件的末尾没有换行符 - 它无法计算文件中的最后一行.

这种方法对我来说效果更好:

public int countLines(String filename) throws IOException {
    LineNumberReader reader  = new LineNumberReader(new FileReader(filename));
int cnt = 0;
String lineRead = "";
while ((lineRead = reader.readLine()) != null) {}

cnt = reader.getLineNumber(); 
reader.close();
return cnt;
}



6> Nathan Ryan..:

我知道这是一个古老的问题,但是接受的解决方案与我需要做的并不完全相符.所以,我改进它以接受各种行终止符(而不仅仅是换行符)并使用指定的字符编码(而不是ISO-8859- n).所有在一个方法(适当的重构):

public static long getLinesCount(String fileName, String encodingName) throws IOException {
    long linesCount = 0;
    File file = new File(fileName);
    FileInputStream fileIn = new FileInputStream(file);
    try {
        Charset encoding = Charset.forName(encodingName);
        Reader fileReader = new InputStreamReader(fileIn, encoding);
        int bufferSize = 4096;
        Reader reader = new BufferedReader(fileReader, bufferSize);
        char[] buffer = new char[bufferSize];
        int prevChar = -1;
        int readCount = reader.read(buffer);
        while (readCount != -1) {
            for (int i = 0; i < readCount; i++) {
                int nextChar = buffer[i];
                switch (nextChar) {
                    case '\r': {
                        // The current line is terminated by a carriage return or by a carriage return immediately followed by a line feed.
                        linesCount++;
                        break;
                    }
                    case '\n': {
                        if (prevChar == '\r') {
                            // The current line is terminated by a carriage return immediately followed by a line feed.
                            // The line has already been counted.
                        } else {
                            // The current line is terminated by a line feed.
                            linesCount++;
                        }
                        break;
                    }
                }
                prevChar = nextChar;
            }
            readCount = reader.read(buffer);
        }
        if (prevCh != -1) {
            switch (prevCh) {
                case '\r':
                case '\n': {
                    // The last line is terminated by a line terminator.
                    // The last line has already been counted.
                    break;
                }
                default: {
                    // The last line is terminated by end-of-file.
                    linesCount++;
                }
            }
        }
    } finally {
        fileIn.close();
    }
    return linesCount;
}

这个解决方案在速度上与可接受的解决方案相当,在我的测试中慢了大约4%(尽管Java中的时序测试非常不可靠).


).所有在一个方法(适当的重构):

7> 小智..:

我测试了上述用于计数行的方法,这是我在系统上测试的不同方法的观察结果

文件大小:1.6 Gb方法:

    使用扫描仪:约35秒

    使用BufferedReader:大约5秒钟

    使用Java 8:大约5s

    使用LineNumberReader:大约5秒

此外,Java8方法似乎非常方便:Files.lines(Paths.get(filePath),Charset.defaultCharset())。count()[返回类型:long]

推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有