2009-08-14 79 views
49

我有一個大文件。它包括大約3.000-20.000行。如何使用Java獲得文件中行的總數?如何以有效的方式獲取文件中的行數?

+1

從您的評論的答案來看,你正在尋找的字是「有效的」,而不是「有效」 。 – AakashM 2009-08-14 13:51:55

+0

是的,您是對的 – firstthumb 2009-08-14 13:56:00

+0

@Firstthumb:*人們回覆後請不要刪除評論*。這使得人們遲到的節目讓人感到困惑。 – Telemachus 2009-08-14 13:57:56

回答

84
BufferedReader reader = new BufferedReader(new FileReader("file.txt")); 
int lines = 0; 
while (reader.readLine() != null) lines++; 
reader.close(); 

更新:要回答這裏提出的性能問題,我做了一個測量。第一件事:20.000行太少,爲了讓程序運行一段顯着的時間。我創建了500萬行文本文件。這個解決方案(以java開頭,沒有像-server或-XX選項這樣的參數)在我的盒子上需要大約11秒。與wc -l(UNIX命令行工具來計算行數)相同,11秒。解讀每一個字符並尋找'\ n'的解決方案需要104秒,是9-10倍。

+0

你的意思是什麼效率?性能?在這種情況下,你將沒有更好的辦法,因爲行可以有不同的長度,你將不得不讀取完整的文件,來計算行數(wc也是這樣)。如果您談論的是編程效率,我相信您可以將它放在一個實用程序方法中(或者已經有一些共同的庫)。 – Mnementh 2009-08-14 13:55:12

+0

@Firstthumb。也許效率不高,但誰在乎。他只計算20k線,非常小。這段代碼得到我的投票是最簡單的。 – 2009-08-14 13:55:57

+0

因爲它擴展了BufferedReader,LineNumberReader的效率如何? – Narayan 2009-08-15 07:56:48

4

通過讀取文件並計算換行符的數量。一次一行地讀取Java文件的簡單方法是java.util.Scanner類。

0

逐行讀取文件,每行增加一個計數器,直到讀完整個文件。

29

使用LineNumberReader

public static int countLines(File aFile) throws IOException { 
    LineNumberReader reader = null; 
    try { 
     reader = new LineNumberReader(new FileReader(aFile)); 
     while ((reader.readLine()) != null); 
     return reader.getLineNumber(); 
    } catch (Exception ex) { 
     return -1; 
    } finally { 
     if(reader != null) 
      reader.close(); 
    } 
} 
+2

您可能還需要關閉()閱讀器。 – 2009-08-15 07:03:47

+0

yup;完成謝謝:D – Narayan 2009-08-15 07:49:38

+2

您可能要檢查讀者!= null在finally塊 – dfa 2009-08-15 08:32:13

-2

緩衝的讀者是矯枉過正

Reader r = new FileReader("f.txt"); 

int count = 0; 
int nextchar = 0; 
while (nextchar != -1){ 
     nextchar = r.read(); 
     if (nextchar == Character.getNumericValue('\n')){ 
      count++; 
     } 
    } 

我一個簡單的例子,搜索已經createde那個那其實挺可憐的。爲單個字符重複調用read()不是最優的。有關示例和測量,請參閱here

+2

BufferedReader很好地處理不同的行尾。您的解決方案忽略Mac行結尾('\ r')。這可能是好的。無論如何,您的解決方案並不是實時從文件中讀取的。我想你忘了一行。 – Mnementh 2009-08-14 13:58:41

+5

這裏有什麼改變nextchar?如果你打算在每次迭代時調用read(),我強烈懷疑BufferedReader的方法會快得多* – 2009-08-14 13:59:29

+0

這是個想法; - /我想寫一個最簡單的例子。我想知道速度差異會是什麼? – NSherwin 2009-08-14 14:01:37

2

以前的所有答案都建議閱讀整個文件並計算在執行此操作時發現的換行數量。你評論說有些人「不夠有效」,但那是你做到這一點的唯一方法。文件中的「行」不是別的,它只是一個簡單的字符。要計算該字符,您必須查看文件中的每個字符。

對不起,但你別無選擇。 :-)

2

如果已發佈的答案不夠快,您可能需要尋找針對您的特定問題的解決方案。

例如,如果這些文本文件是隻附加到的日誌,並且您經常需要知道其中的行數,則可以創建索引。該索引將包含文件中的行數,文件上次修改時間以及文件大小。這可以讓你重新計算文件中的行數,方法是跳過你已經看過的所有行,然後只讀新行。

+0

+1這可能是一個合適的在線算法。 – zeroin23 2009-08-14 14:57:58

-1

純Java中最快的解決方案可能是將文件作爲字節使用NIO通道讀入大型ByteBuffer中。然後根據您對文件編碼方案的瞭解,按照相關的行分隔符約定計算編碼的CR和/或NL字節。

的關鍵在於最大限度地提高吞吐量將是:

  • 請務必閱讀大塊的文件,
  • 避免從一個緩衝區複製到另一個字節,
  • 避免複製/轉換字節轉換成字符,並且避免分配對象來表示文件行。

實際的代碼對我來說太複雜了。此外,OP並沒有要求最快的解決方案。

1

試試unix「wc」命令。我不是指使用它,我的意思是下載源代碼並查看它們是如何實現的。它可能在c中,但可以輕鬆地將行爲移植到java。製作你自己的問題是考慮到最終的cr/lf問題。

3

這大約是有效的,因爲它可以得到的,緩衝的二進制讀,沒有字符串轉換,

FileInputStream stream = new FileInputStream("/tmp/test.txt"); 
byte[] buffer = new byte[8192]; 
int count = 0; 
int n; 
while ((n = stream.read(buffer)) > 0) { 
    for (int i = 0; i < n; i++) { 
     if (buffer[i] == '\n') count++; 
    } 
} 
stream.close(); 
System.out.println("Number of lines: " + count); 
2

快速和骯髒的,但它的工作:

import java.io.*; 

public class Counter { 

    public final static void main(String[] args) throws IOException { 
     if (args.length > 0) { 
      File file = new File(args[0]); 
      System.out.println(countLines(file)); 
     } 
    } 

    public final static int countLines(File file) throws IOException { 
     ProcessBuilder builder = new ProcessBuilder("wc", "-l", file.getAbsolutePath()); 
     Process process = builder.start(); 
     InputStream in = process.getInputStream(); 
     LineNumberReader reader = new LineNumberReader(new InputStreamReader(in)); 
     String line = reader.readLine(); 
     if (line != null) { 
      return Integer.parseInt(line.trim().split(" ")[0]); 
     } else { 
      return -1; 
     } 
    } 

} 
+0

一個副作用,這個解決方案不是跨平臺的。 – Stephan 2015-05-20 06:32:35

9

我找到了一些解決方案爲此,它可能對您有用

下面是代碼片段,用於統計文件中的行數。

File file = new File("/mnt/sdcard/abc.txt"); 
    LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(file)); 
    lineNumberReader.skip(Long.MAX_VALUE); 
    int lines = lineNumberReader.getLineNumber(); 
    lineNumberReader.close(); 
+1

結果是行'count - 1' – MariuszS 2014-06-18 11:19:25

+1

實際上結果是'lines + 1' – 2016-10-12 02:53:54

+0

結果是getLineNumber()加1因爲行索引從0開始 – 2017-09-05 21:16:05

3

你需要確切的行數還是隻有它的近似值?我碰巧並行處理大文件,而且通常不需要知道確切的行數 - 然後我恢復採樣。將文件分成10個1MB塊並在每個塊中進行計數,然後將其乘以10,您將收到相當不錯的行計數。

2

這個解決方案比在1380萬行文件上測試的最高評分答案要快3.6倍。它只是將這些字節讀入一個緩衝區並對\n個字符進行計數。您可以使用緩衝區大小,但在我的機器上,超過8KB的任何內容都不會使代碼更快。

private int countLines(File file) throws IOException { 
    int lines = 0; 

    FileInputStream fis = new FileInputStream(file); 
    byte[] buffer = new byte[BUFFER_SIZE]; // BUFFER_SIZE = 8 * 1024 
    int read; 

    while ((read = fis.read(buffer)) != -1) { 
     for (int i = 0; i < read; i++) { 
      if (buffer[i] == '\n') lines++; 
     } 
    } 

    fis.close(); 

    return lines; 
} 
+0

我不知道如果使用預先編譯的RegEx模式會使它更快或更慢。我相信,它會做的是與所有行結局一起工作。而且,我認爲這也可能讓它變得更快。 – ingyhere 2013-11-18 01:46:28

+0

上述的一些解決方案可以利用緩衝,如果好處有幫助的話。例如,「新的LineNumberReader(新FileReader(theFilePathStr),8096)」或其他。 – ingyhere 2013-11-18 01:48:43

+0

注意字符編碼... – 2016-09-02 20:40:55

1

舊的帖子,但我有一個解決方案,可能是有用的下一個人。 爲什麼不使用文件長度來知道進展是什麼?當然,線必須是幾乎相同的大小,但它非常適用於大型文件。

public static void main(String[] args) throws IOException { 
    File file = new File("yourfilehere"); 
    double fileSize = file.length(); 
    System.out.println("=======> File size = " + fileSize); 
    InputStream inputStream = new FileInputStream(file); 
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "iso-8859-1"); 
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 
    int totalRead = 0; 
    try { 
     while (bufferedReader.ready()) { 
      String line = bufferedReader.readLine(); 
      // LINE PROCESSING HERE 
      totalRead += line.length() + 1; // we add +1 byte for the newline char. 
      System.out.println("Progress ===> " + ((totalRead/fileSize) * 100) + " %"); 
     } 
    } finally { 
     bufferedReader.close(); 
    } 
} 

它允許看到的進展而對文件做任何全讀。我知道這取決於很多元素,但我希望它會是有用的:)。

[版] 下面是帶估計時間的版本。我放了一些SYSO來顯示進度和估計。我看到你在處理足夠的線後有很好的估計錯誤(我嘗試了10M線,治療1%後,時間估計精確到95%)。 我知道,一些值必須在變量中設置。此代碼很快寫入,但對我來說已經有用了。希望它也適合你:)。

long startProcessLine = System.currentTimeMillis(); 
    int totalRead = 0; 
    long progressTime = 0; 
    double percent = 0; 
    int i = 0; 
    int j = 0; 
    int fullEstimation = 0; 
    try { 
     while (bufferedReader.ready()) { 
      String line = bufferedReader.readLine(); 
      totalRead += line.length() + 1; 
      progressTime = System.currentTimeMillis() - startProcessLine; 
      percent = (double) totalRead/fileSize * 100; 
      if ((percent > 1) && i % 10000 == 0) { 
       int estimation = (int) ((progressTime/percent) * (100 - percent)); 
       fullEstimation += progressTime + estimation; 
       j++; 
       System.out.print("Progress ===> " + percent + " %"); 
       System.out.print(" - current progress : " + (progressTime) + " milliseconds"); 
       System.out.print(" - Will be finished in ===> " + estimation + " milliseconds"); 
       System.out.println(" - estimated full time => " + (progressTime + estimation)); 
      } 
      i++; 
     } 
    } finally { 
     bufferedReader.close(); 
    } 
    System.out.println("Ended in " + (progressTime) + " seconds"); 
    System.out.println("Estimative average ===> " + (fullEstimation/j)); 
    System.out.println("Difference: " + ((((double) 100/(double) progressTime)) * (progressTime - (fullEstimation/j))) + "%"); 

如果您認爲這是一個好的解決方案,請隨時改進此代碼。

0

在我的測試中,其他答案在118.5k行文件上花費〜150-300ms。 以下內容需要1ms,但僅爲近似值(報告爲117k行),並且取決於具有相似大小的每一行。

private static void countSize(File file) { 
    long fileLength = file.length(); 
    BufferedReader reader = null; 
    try { 
    reader = new BufferedReader(new FileReader(file)); 
    //Skip header as it is of different size 
    reader.readLine(); 
    String text = reader.readLine(); 
    int lineLength = text.length(); 
    long lines = fileLength/lineLength; 
    System.out.println(lines); 
    } catch(IOException e) { 
    e.printStackTrace(); 
    } finally { 
    if(reader != null) { 
     try { 
     reader.close(); 
     } catch(IOException e) { 
     //no-op 
     } 
    } 
    } 
} 
13

的Java 8+具有使用NIO一個很不錯的一小段路:

Path path = Paths.get("./big_file.txt"); 
long lineCount = Files.lines(path).count(); 
+0

牀的解決方案。我們可以在字符集中遇到問題 – Mikhail 2016-05-25 10:12:08

+1

默認情況下,字符集默認爲UTF-8 – 2016-10-24 23:05:59

相關問題