จำนวนบรรทัดในไฟล์ใน Java


213

ฉันใช้ไฟล์ข้อมูลขนาดใหญ่บางครั้งฉันจำเป็นต้องรู้จำนวนบรรทัดในไฟล์เหล่านี้เท่านั้นโดยปกติฉันจะเปิดอ่านแล้วอ่านทีละบรรทัดจนกว่าจะถึงจุดสิ้นสุดไฟล์

ฉันสงสัยว่ามีวิธีที่ชาญฉลาดกว่านี้หรือไม่

คำตอบ:


237

นี่เป็นรุ่นที่เร็วที่สุดที่ฉันค้นพบจนถึงตอนนี้เร็วกว่า readLines ประมาณ 6 เท่า ในไฟล์บันทึก 150MB จะใช้เวลา 0.35 วินาทีกับ 2.40 วินาทีเมื่อใช้ readLines () เพื่อความสนุกสนานคำสั่ง wc -l ของ linux ใช้เวลา 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 1/2 ปีต่อมา: ฉันไม่เคยมีประสบการณ์เกี่ยวกับจาวา แต่จริงๆแล้วฉันพยายามเปรียบเทียบมาตรฐานนี้กับทาง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<readChars; ++i) {
                if (c[i] == '\n') {
                    ++count;
                }
            }
            readChars = is.read(c);
        }

        return count == 0 ? 1 : count;
    } finally {
        is.close();
    }
}

เกณฑ์มาตรฐาน resuls สำหรับไฟล์ข้อความ 1.3GB แกน y ในไม่กี่วินาที ฉันได้ดำเนินการวิ่ง 100 System.nanoTime()กับแฟ้มเดียวกันและวัดการทำงานในแต่ละที่มี คุณจะเห็นว่าcountLinesOldมีค่าผิดปกติเล็กน้อยและcountLinesNewไม่มีเลยและในขณะที่มันเร็วขึ้นเพียงเล็กน้อยความแตกต่างนั้นมีนัยสำคัญทางสถิติ LineNumberReaderช้าลงอย่างชัดเจน

พล็อตเกณฑ์มาตรฐาน


5
BufferedInputStream ควรทำการบัฟเฟอร์สำหรับคุณดังนั้นฉันไม่เห็นว่าการใช้อาร์เรย์ไบต์ [] จะทำให้เร็วขึ้นได้อย่างไร คุณไม่น่าจะทำอะไรได้ดีไปกว่าการใช้ readLine () ซ้ำ ๆ อยู่ดี (เนื่องจาก API จะได้รับการปรับปรุงให้ดีที่สุด
wds

54
คุณกำลังจะปิด InputStream นั้นเมื่อคุณทำเสร็จแล้วใช่ไหม
bendin

5
หากการบัฟเฟอร์ช่วยได้เพราะ BufferedInputStream บัฟเฟอร์ 8K เป็นค่าเริ่มต้น เพิ่ม byte [] ของคุณเป็นขนาดนี้หรือใหญ่กว่าและคุณสามารถดร็อป BufferedInputStream เช่นลอง 1024 * 1024 ไบต์
Peter Lawrey

8
สองสิ่ง: (1) คำจำกัดความของตัวยุติบรรทัดในแหล่งที่มาของ Java คือการขึ้นบรรทัดใหม่, การป้อนบรรทัดหรือการขึ้นบรรทัดใหม่ตามด้วยการป้อนบรรทัด โซลูชันของคุณจะไม่ทำงานสำหรับ CR ที่ใช้เป็นตัวยุติบรรทัด จริงอยู่ที่ระบบปฏิบัติการเดียวที่ฉันคิดว่าใช้ CR เป็นตัวเริ่มต้นบรรทัดคือ Mac OS ก่อน Mac OS X (2) โซลูชันของคุณใช้การเข้ารหัสอักขระเช่น US-ASCII หรือ UTF-8 การนับจำนวนบรรทัดอาจไม่ถูกต้องสำหรับการเข้ารหัสเช่น UTF-16
Nathan Ryan

2
รหัสดีเลิศ ... สำหรับไฟล์ข้อความขนาด 400mb ใช้เวลาเพียงไม่กี่วินาที ขอบคุณมาก @martinus
user3181500

199

ฉันใช้วิธีแก้ไขปัญหาอื่นฉันพบว่าการนับแถวมีประสิทธิภาพมากขึ้น:

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
}

LineNumberReader's lineNumberฟิลด์เป็นจำนวนเต็ม ... จะไม่ได้เป็นเพียงแค่ห่อสำหรับไฟล์นานกว่า Integer.MAX_VALUE? ทำไมต้องข้ามไปที่นี่นาน?
epb

1
การเพิ่มหนึ่งรายการเข้าไปในการนับนั้นไม่ถูกต้องจริง wc -lนับจำนวนตัวอักษรขึ้นบรรทัดใหม่ในไฟล์ ใช้งานได้เนื่องจากทุกบรรทัดถูกยกเลิกด้วยการขึ้นบรรทัดใหม่รวมถึงบรรทัดสุดท้ายในไฟล์ ทุกบรรทัดมีอักขระขึ้นบรรทัดใหม่รวมถึงบรรทัดว่างดังนั้นจำนวนตัวอักษรขึ้นบรรทัดใหม่ == จำนวนบรรทัดในไฟล์ ตอนนี้lineNumberตัวแปรในFileNumberReaderยังแสดงถึงจำนวนตัวอักษรขึ้นบรรทัดใหม่ที่เห็น มันเริ่มต้นที่ศูนย์ก่อนที่จะพบบรรทัดใหม่และเพิ่มขึ้นเมื่อเห็นบรรทัดใหม่ทุกตัว ดังนั้นโปรดอย่าเพิ่มหนึ่งหมายเลขลงในหมายเลขบรรทัดโปรด
Alexander Torstling

1
@PB_MLT: แม้ว่าคุณจะถูกต้องว่าไฟล์ที่มีบรรทัดเดียวโดยไม่มีการขึ้นบรรทัดใหม่จะถูกรายงานเป็น 0 บรรทัดนี่คือวิธีwc -lรายงานไฟล์ประเภทนี้เช่นกัน โปรดดูstackoverflow.com/questions/729692/…
Alexander Torstling

@PB_MLT: คุณได้รับปัญหาตรงข้ามหากไฟล์ประกอบด้วยบรรทัดใหม่เพียงอย่างเดียว อัลโกที่แนะนำของคุณจะกลับมาเป็น 0 และwc -lจะคืน 1 ฉันสรุปว่าวิธีการทั้งหมดมีข้อบกพร่องและดำเนินการอย่างใดอย่างหนึ่งโดยขึ้นอยู่กับว่าฉันต้องการให้ประพฤติอย่างไร
Alexander Torstling

3
ฉันลงคะแนนการตอบสนองนี้แล้วเพราะดูเหมือนว่าไม่มีใครในคุณที่ได้ทำการเปรียบเทียบ
amstegraf

30

คำตอบที่ยอมรับมีข้อผิดพลาดเดียวสำหรับไฟล์หลายบรรทัดที่ไม่ได้ขึ้นบรรทัดใหม่ ไฟล์หนึ่งบรรทัดที่ลงท้ายด้วยไม่มีบรรทัดใหม่จะส่งคืน 1 แต่ไฟล์สองบรรทัดที่ลงท้ายด้วยไม่มีบรรทัดใหม่จะส่งคืน 1 เช่นกัน นี่คือการใช้งานโซลูชันที่ยอมรับซึ่งแก้ไขปัญหานี้ ปลายไม่มีการตรวจสอบสายใหม่จะสิ้นเปลืองสำหรับทุกอย่างยกเว้นการอ่านครั้งสุดท้าย แต่ควรใช้เวลาเล็กน้อยเมื่อเทียบกับฟังก์ชั่นโดยรวม

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();
    }
}

6
จับดี. ไม่แน่ใจว่าทำไมคุณไม่เพียงแค่แก้ไขคำตอบที่ได้รับการยอมรับและจดบันทึกในความคิดเห็น คนส่วนใหญ่จะไม่อ่านข้อมูลนี้
Ryan

@ Ryan มันไม่รู้สึกถูกต้องที่จะแก้ไขคำตอบที่ยอมรับได้อายุ 4 ปีที่มี upvotes มากกว่า 90 รายการ
DMulligan

@AFinkelstein ฉันรู้สึกว่าเป็นสิ่งที่ทำให้เว็บไซต์นี้ยอดเยี่ยมมากซึ่งคุณสามารถแก้ไขคำตอบที่ได้รับการโหวตสูงสุด
เซบาสเตียน

3
วิธีนี้ไม่ได้จัดการกับ carriage return (\ r) และ carriage return ตามด้วย linefeed (\ r \ n)
Simon Brandhof - SonarSource

@Simon Brandhof ฉันสับสนว่าทำไมการรับคืนของสายการบินจึงถูกนับเป็นอีกบรรทัดหนึ่ง A "\ n" เป็นตัวดึงข้อมูลบรรทัดการขึ้นบรรทัดใหม่ดังนั้นใครก็ตามที่เขียน "\ r \ n" ไม่เข้าใจอะไรบางอย่าง ... นอกจากนี้เขากำลังค้นหาคำสั่งถ่านดังนั้นฉันค่อนข้างแน่ใจว่ามีคนใช้ "\ r \ n "มันจะยังคงจับ" \ n "และนับบรรทัด ฉันคิดว่าเขาทำได้ดี อย่างไรก็ตามมีหลายสถานการณ์ที่ไม่เพียงพอต่อการนับจำนวนบรรทัด
nckbrz

22

กับ คุณสามารถใช้สตรีม:

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

1
รหัสมีข้อผิดพลาด เรียบง่าย แต่ช้ามาก ... ลองดูคำตอบของฉันด้านล่าง (ด้านบน)
Ernestas Gruodis

12

คำตอบที่มีการนับเมธอด () ด้านบนให้ฉันบรรทัด miscounts ถ้าไฟล์ไม่ได้ขึ้นบรรทัดใหม่ในตอนท้ายของไฟล์ - มันไม่สามารถนับบรรทัดสุดท้ายในไฟล์

วิธีนี้ใช้ได้ผลดีกว่าสำหรับฉัน:

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;
}

ในกรณีนี้มีความจำเป็นของการใช้ LineNumberReader ไม่เพียงใช้ BufferedReader ในกรณีที่ you'l cntมีความยืดหยุ่นในการใช้งานประเภทข้อมูลนานสำหรับ
Syed Aqeel Ashiq

[INFO] PMD ความล้มเหลว: xx: 19 กฎ: EmptyWhileStmt ลำดับความสำคัญ: 3 หลีกเลี่ยงการว่างเปล่าในขณะที่คำสั่ง
Chhorn Elit

8

ฉันรู้ว่านี่เป็นคำถามเก่า แต่วิธีแก้ปัญหาที่ยอมรับไม่ตรงกับสิ่งที่ฉันต้องการให้ทำ ดังนั้นฉันจึงกลั่นตัวเพื่อยอมรับตัวเลือกบรรทัดต่าง ๆ (แทนที่จะเป็นเพียงแค่ตัวป้อนบรรทัด) และใช้การเข้ารหัสอักขระที่ระบุ (แทนที่จะเป็น ISO-8859- n ) ทั้งหมดในหนึ่งวิธี (refactor ตามความเหมาะสม):

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 จะไม่น่าเชื่อถือ)


8

ฉันทดสอบวิธีการด้านบนเพื่อนับจำนวนบรรทัดและนี่คือข้อสังเกตของฉันสำหรับวิธีการต่าง ๆ ที่ทดสอบในระบบของฉัน

ขนาดไฟล์: 1.6 Gb

  1. ใช้สแกนเนอร์ : ประมาณ 35 วินาที
  2. ใช้ BufferedReader : ประมาณ 5s
  3. ใช้ Java 8 : 5s โดยประมาณ
  4. ใช้ LineNumberReader : ประมาณ 5s

ยิ่งไปกว่านั้นวิธีJava8ดูเหมือนว่ามีประโยชน์มาก:

Files.lines(Paths.get(filePath), Charset.defaultCharset()).count()
[Return type : long]

5
/**
 * Count file rows.
 *
 * @param file file
 * @return file row count
 * @throws IOException
 */
public static long getLineCount(File file) throws IOException {

    try (Stream<String> lines = Files.lines(file.toPath())) {
        return lines.count();
    }
}

ทดสอบกับ JDK8_u31 แต่ประสิทธิภาพแท้จริงช้าเมื่อเปรียบเทียบกับวิธีนี้:

/**
 * Count file rows.
 *
 * @param file file
 * @return file row count
 * @throws IOException
 */
public static long getLineCount(File file) throws IOException {

    try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(file), 1024)) {

        byte[] c = new byte[1024];
        boolean empty = true,
                lastEmpty = false;
        long count = 0;
        int read;
        while ((read = is.read(c)) != -1) {
            for (int i = 0; i < read; i++) {
                if (c[i] == '\n') {
                    count++;
                    lastEmpty = true;
                } else if (lastEmpty) {
                    lastEmpty = false;
                }
            }
            empty = false;
        }

        if (!empty) {
            if (count == 0) {
                count = 1;
            } else if (!lastEmpty) {
                count++;
            }
        }

        return count;
    }
}

ผ่านการทดสอบและเร็วมาก


สิ่งนี้ไม่ถูกต้อง ทำการทดลองกับโค้ดของคุณและวิธีการจะช้าลงเสมอ Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1และจำนวนบรรทัดก็ผิดด้วย
อ๊ะคิด

ฉันทดสอบกับเครื่อง 32 บิต บางทีบน 64 บิตอาจเป็นผลลัพธ์ที่แตกต่าง .. และมันก็เป็นความแตกต่าง 10 ครั้งหรือมากกว่านั้นอย่างที่ฉันจำได้ คุณช่วยโพสต์ข้อความเพื่อนับบรรทัดได้ไหม? คุณสามารถใช้ Notepad2 เพื่อดูตัวแบ่งบรรทัดเพื่อความสะดวก
Ernestas Gruodis

นั่นอาจเป็นความแตกต่าง
แย่จังคิด

หากคุณใส่ใจกับประสิทธิภาพการทำงานคุณไม่ควรใช้ a BufferedInputStreamเมื่อคุณจะอ่านลงในบัฟเฟอร์ของคุณเอง นอกจากนี้แม้ว่าวิธีการของคุณอาจมีข้อได้เปรียบด้านประสิทธิภาพเพียงเล็กน้อย แต่ก็มีความยืดหยุ่นเนื่องจากไม่รองรับตัววาง\rสายแบบเดี่ยว(MacOS เก่า) อีกต่อไปและไม่รองรับการเข้ารหัสทุกตัว
Holger

4

วิธีการตรงไปข้างหน้าโดยใช้เครื่องสแกนเนอร์

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);
    }

3

ฉันสรุปได้ว่า wc -l : วิธีการนับการขึ้นบรรทัดใหม่นั้นใช้ได้ผลตอบแทนที่ไม่ง่ายในไฟล์ที่บรรทัดสุดท้ายไม่ได้ขึ้นบรรทัดใหม่

และวิธีการแก้ปัญหา @ er.vikas ขึ้นอยู่กับ LineNumberReader แต่เพิ่มหนึ่งในการนับบรรทัดส่งกลับผลลัพธ์ที่ไม่ง่ายในไฟล์ที่บรรทัดสุดท้ายจะจบลงด้วยการขึ้นบรรทัดใหม่

ฉันจึงสร้างอัลโกซึ่งจัดการดังต่อไปนี้:

@Test
public void empty() throws IOException {
    assertEquals(0, count(""));
}

@Test
public void singleNewline() throws IOException {
    assertEquals(1, count("\n"));
}

@Test
public void dataWithoutNewline() throws IOException {
    assertEquals(1, count("one"));
}

@Test
public void oneCompleteLine() throws IOException {
    assertEquals(1, count("one\n"));
}

@Test
public void twoCompleteLines() throws IOException {
    assertEquals(2, count("one\ntwo\n"));
}

@Test
public void twoLinesWithoutNewlineAtEnd() throws IOException {
    assertEquals(2, count("one\ntwo"));
}

@Test
public void aFewLines() throws IOException {
    assertEquals(5, count("one\ntwo\nthree\nfour\nfive\n"));
}

และดูเหมือนว่านี้:

static long countLines(InputStream is) throws IOException {
    try(LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is))) {
        char[] buf = new char[8192];
        int n, previousN = -1;
        //Read will return at least one byte, no need to buffer more
        while((n = lnr.read(buf)) != -1) {
            previousN = n;
        }
        int ln = lnr.getLineNumber();
        if (previousN == -1) {
            //No data read at all, i.e file was empty
            return 0;
        } else {
            char lastChar = buf[previousN - 1];
            if (lastChar == '\n' || lastChar == '\r') {
                //Ending with newline, deduct one
                return ln;
            }
        }
        //normal case, return line number + 1
        return ln + 1;
    }
}

หากคุณต้องการผลลัพธ์ที่เข้าใจง่ายคุณสามารถใช้สิ่งนี้ หากคุณต้องการwc -lความเข้ากันได้ให้ใช้โซลูชัน @ er.vikas อย่างง่าย แต่ไม่ต้องเพิ่มหนึ่งรายการในผลลัพธ์และลองข้ามใหม่อีกครั้ง:

try(LineNumberReader lnr = new LineNumberReader(new FileReader(new File("File1")))) {
    while(lnr.skip(Long.MAX_VALUE) > 0){};
    return lnr.getLineNumber();
}

2

วิธีการเกี่ยวกับการใช้ระดับกระบวนการจากภายในรหัส Java? จากนั้นอ่านเอาต์พุตของคำสั่ง

Process p = Runtime.getRuntime().exec("wc -l " + yourfilename);
p.waitFor();

BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
int lineCount = 0;
while ((line = b.readLine()) != null) {
    System.out.println(line);
    lineCount = Integer.parseInt(line);
}

ต้องลองดู จะโพสต์ผลลัพธ์


1

หากคุณไม่มีโครงสร้างดัชนีคุณจะไม่สามารถอ่านไฟล์ทั้งหมดได้ แต่คุณสามารถปรับให้เหมาะสมได้โดยหลีกเลี่ยงการอ่านทีละบรรทัดและใช้ regex เพื่อจับคู่ตัวยุติบรรทัดทั้งหมด


ฟังดูเหมือนความคิดที่เรียบร้อย ใครลองและมี regexp มันได้หรือไม่
willcodejavaforfood

1
ฉันสงสัยว่ามันเป็นความคิดที่ดี: มันจะต้องอ่านไฟล์ทั้งหมดในครั้งเดียว (martinus หลีกเลี่ยงสิ่งนี้) และ regexes นั้น overkill (และช้ากว่า) สำหรับการใช้งานดังกล่าว (ค้นหาง่ายๆของ char แบบคงที่)
PhiLho

@ จะมีอะไรเกี่ยวกับ / \ n / @PhiLo: ผู้บริหาร Regex เป็นเครื่องที่มีประสิทธิภาพสูง ยกเว้นข้อแม้อ่านทุกอย่างในหน่วยความจำฉันไม่คิดว่าการติดตั้งด้วยตนเองจะเร็วขึ้น
David Schmitt

1

ทางออกที่ตลกนี้ใช้ได้ดีจริง ๆ !

public static int countLines(File input) throws IOException {
    try (InputStream is = new FileInputStream(input)) {
        int count = 1;
        for (int aChar = 0; aChar != -1;aChar = is.read())
            count += aChar == '\n' ? 1 : 0;
        return count;
    }
}

0

บนระบบที่ใช้ Unix ให้ใช้wcคำสั่งบนบรรทัดคำสั่ง


@IainmH ข้อเสนอแนะที่สองของคุณเพียงแค่นับจำนวนรายการในไดเรกทอรีปัจจุบัน ไม่ใช่สิ่งที่ตั้งใจ? (หรือขอโดย OP)
เทพพอล

@IainMH: นั่นคือสิ่งที่ wc ทำอยู่แล้ว (อ่านไฟล์นับจบบรรทัด)
PhiLho

@PhiLho คุณต้องใช้สวิตช์ -l เพื่อนับจำนวนบรรทัด (คุณไม่? - จะได้รับในขณะที่)
เลน Holder

@Paul - คุณแน่นอน 100% ถูกต้อง การป้องกันอย่างเดียวของฉันคือฉันโพสต์สิ่งนั้นก่อนกาแฟ ตอนนี้ฉันมีความคมชัดเท่าปุ่ม : D
ผู้ถือ Iain

0

วิธีเดียวที่จะทราบจำนวนไฟล์ที่มีอยู่ในไฟล์คือการนับมัน แน่นอนคุณสามารถสร้างตัวชี้วัดจากข้อมูลของคุณโดยให้ความยาวเฉลี่ยหนึ่งบรรทัดจากนั้นรับขนาดไฟล์และหารด้วย avg ความยาว แต่นั่นจะไม่ถูกต้อง


1
downvote ที่น่าสนใจไม่ว่าเครื่องมือบรรทัดคำสั่งใดที่คุณใช้พวกเขาทั้งหมดทำสิ่งเดียวกันอย่างไรก็ตามภายในเท่านั้น ไม่มีวิธีที่วิเศษในการหาจำนวนบรรทัดพวกเขาจะต้องนับด้วยมือ แน่ใจว่าจะสามารถบันทึกเป็นข้อมูลเมตา แต่ที่ทั้งเรื่องอื่น ...
Esko

0

รหัสเพิ่มประสิทธิภาพที่ดีที่สุดสำหรับไฟล์หลายบรรทัดที่ไม่มีอักขระบรรทัดใหม่ ('\ n') ที่ EOF

/**
 * 
 * @param filename
 * @return
 * @throws IOException
 */
public static int countLines(String filename) throws IOException {
    int count = 0;
    boolean empty = true;
    FileInputStream fis = null;
    InputStream is = null;
    try {
        fis = new FileInputStream(filename);
        is = new BufferedInputStream(fis);
        byte[] c = new byte[1024];
        int readChars = 0;
        boolean isLine = false;
        while ((readChars = is.read(c)) != -1) {
            empty = false;
            for (int i = 0; i < readChars; ++i) {
                if ( c[i] == '\n' ) {
                    isLine = false;
                    ++count;
                }else if(!isLine && c[i] != '\n' && c[i] != '\r'){   //Case to handle line count where no New Line character present at EOF
                    isLine = true;
                }
            }
        }
        if(isLine){
            ++count;
        }
    }catch(IOException e){
        e.printStackTrace();
    }finally {
        if(is != null){
            is.close();    
        }
        if(fis != null){
            fis.close();    
        }
    }
    LOG.info("count: "+count);
    return (count == 0 && !empty) ? 1 : count;
}

0

เครื่องสแกนด้วย regex:

public int getLineCount() {
    Scanner fileScanner = null;
    int lineCount = 0;
    Pattern lineEndPattern = Pattern.compile("(?m)$");  
    try {
        fileScanner = new Scanner(new File(filename)).useDelimiter(lineEndPattern);
        while (fileScanner.hasNext()) {
            fileScanner.next();
            ++lineCount;
        }   
    }catch(FileNotFoundException e) {
        e.printStackTrace();
        return lineCount;
    }
    fileScanner.close();
    return lineCount;
}

ยังไม่ได้โอเวอร์คล็อกมัน


-2

ถ้าคุณใช้สิ่งนี้

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;
}

คุณไม่สามารถเรียกใช้แถวขนาดใหญ่ได้เช่น 100K แถวเนื่องจากการกลับมาจาก reader.getLineNumber นั้นเป็น int คุณต้องการข้อมูลชนิดยาวในการประมวลผลแถวสูงสุด ..


14
intสามารถเก็บค่าขึ้นไปประมาณ 2 พันล้าน หากคุณกำลังโหลดไฟล์ที่มีมากกว่า 2 พันล้านบรรทัดคุณจะพบปัญหามากเกินไป ที่กล่าวว่าหากคุณกำลังโหลดไฟล์ข้อความที่ไม่มีดัชนีที่มีมากกว่าสองพันล้านบรรทัดคุณอาจมีปัญหาอื่น ๆ
Adam Norberg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.