जावा में एक फ़ाइल में लाइनों की संख्या


213

मैं बड़ी डेटा फ़ाइलों का उपयोग करता हूं, कभी-कभी मुझे केवल इन फ़ाइलों में लाइनों की संख्या जानने की आवश्यकता होती है, आमतौर पर मैं उन्हें खोलता हूं और उन्हें लाइन से पढ़ता हूं जब तक कि मैं फ़ाइल के अंत तक नहीं पहुंचता हूं

मैं सोच रहा था कि क्या ऐसा करने के लिए एक स्मार्ट तरीका है

जवाबों:


237

यह अब तक का सबसे तेज संस्करण है, जो रीडलाइन से लगभग 6 गुना तेज है। 150 एमबी लॉग फ़ाइल पर यह रीडलाइन () का उपयोग करते समय 0.35 सेकंड, बनाम 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();
    }
}

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

बेंचमार्क एक 1.3GB पाठ फ़ाइल के लिए resuls, सेकंड में y अक्ष। मैंने एक ही फ़ाइल के साथ 100 रन बनाए हैं, और प्रत्येक रन को मापा है System.nanoTime()। आप देख सकते हैं कि countLinesOldकुछ आउटलेयर हैं, और countLinesNewकोई भी नहीं है और जबकि यह केवल थोड़ा तेज है, अंतर सांख्यिकीय रूप से महत्वपूर्ण है। LineNumberReaderस्पष्ट रूप से धीमा है।

बेंचमार्क प्लॉट


5
BufferedInputStream आपके लिए बफ़रिंग कर रहा होना चाहिए, इसलिए मैं यह नहीं देखता कि एक मध्यवर्ती बाइट [] सरणी का उपयोग करके इसे कैसे तेज किया जाएगा। आप वैसे भी रीडलाइन () को बार-बार उपयोग करने की अपेक्षा बेहतर नहीं कर सकते (क्योंकि यह एपीआई द्वारा अनुकूलित किया जाएगा)।
wds

54
जब आप इसके साथ हो जाते हैं, तो आप उस InputStream को बंद करने जा रहे हैं, क्या आप नहीं हैं?
बेंडिन

5
यदि बफ़रिंग ने इसमें मदद की, क्योंकि बफ़रडइनप्यूटस्ट्रीम बफ़र डिफ़ॉल्ट रूप से 8K है। अपने बाइट को बढ़ाएँ [] इस आकार या बड़े तक और आप बफ़रडइनप्यूटस्ट्रीम को गिरा सकते हैं। उदा। 1024 * 1024 बाइट्स का प्रयास करें।
पीटर लॉरी

8
दो बातें: (1) जावा स्रोत में एक लाइन टर्मिनेटर की परिभाषा एक गाड़ी वापसी, एक पंक्ति फ़ीड, या एक गाड़ी वापसी एक पंक्ति फ़ीड के बाद है। आपका समाधान सीआर के लिए एक लाइन टर्मिनेटर के रूप में काम नहीं करेगा। दी गई, जिसका एकमात्र OS मैं सोच सकता हूं कि डिफ़ॉल्ट लाइन टर्मिनेटर के रूप में सीआर का उपयोग मैक ओएस एक्स से पहले मैक ओएस है। (2) आपका समाधान यूएस-एएससीआईआई या यूटीएफ -8 जैसे चरित्र एन्कोडिंग को मानता है। यूटीएफ -16 जैसे एनकोडिंग के लिए लाइन की गणना गलत हो सकती है।
नाथन रयान

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के lineNumberक्षेत्र एक पूर्णांक है ... यह सिर्फ Integer.MAX_VALUE से अधिक समय फ़ाइलों के लिए लपेट नहीं होगा? यहाँ एक लंबे समय से लंघन क्यों परेशान?
एपीबी

1
गिनती में एक जोड़ना वास्तव में गलत है। wc -lफ़ाइल में newline वर्णों की संख्या गिना जाता है। यह काम करता है क्योंकि हर लाइन एक नई लाइन के साथ समाप्त हो जाती है, जिसमें एक फाइल में अंतिम लाइन भी शामिल है। प्रत्येक पंक्ति में एक नई रेखा वर्ण होती है, जिसमें खाली रेखाएँ भी शामिल होती हैं, जिससे एक फ़ाइल में नई पंक्ति वर्णों की संख्या == संख्याएँ होती हैं। अब, lineNumberचर FileNumberReaderभी देखी जाने वाली न्यूलाइन वर्णों की संख्या का प्रतिनिधित्व करता है। यह शून्य पर शुरू होता है, इससे पहले कि कोई भी नई लाइन मिली हो, और देखी गई हर नईलाइन चार के साथ बढ़ जाती है। तो कृपया एक पंक्ति संख्या में न जोड़ें।
अलेक्जेंडर टॉर्लिंग

1
@PB_MLT: हालाँकि आप सही कह रहे हैं कि नई लाइन के बिना सिंगल लाइन वाली फाइल 0 लाइनों के रूप में बताई जाएगी, यह wc -lइस तरह की फाइल की रिपोर्ट भी है। इसके अलावा stackoverflow.com/questions/729692/…
अलेक्जेंडर टॉर्स्टिंग

@PB_MLT: यदि फ़ाइल केवल एक नई पंक्ति में हो तो आपको विपरीत समस्या आती है। आपका सुझाव दिया गया अहंकार 0 पर लौटेगा और wc -l1. वापस आ जाएगा। मैंने निष्कर्ष निकाला कि सभी विधियों में खामियां हैं, और एक को लागू किया है कि मैं इसे कैसे व्यवहार करना चाहूंगा, मेरे अन्य उत्तर यहां देखें।
अलेक्जेंडर टॉर्टलिंग

3
मैंने इस प्रतिक्रिया को वोट दिया है, क्योंकि ऐसा लगता है कि आप में से किसी ने भी इसे बेंचमार्क नहीं किया है
amstegraf

30

स्वीकृत उत्तर में मल्टी लाइन फ़ाइलों के लिए एक त्रुटि है, जो कि नई लाइन में समाप्त नहीं होती है। एक नई लाइन के बिना समाप्त होने वाली एक लाइन फ़ाइल 1 वापस आ जाएगी, लेकिन एक नई लाइन के बिना समाप्त होने वाली दो लाइन फ़ाइल 1 भी वापस आ जाएगी। यहां स्वीकृत समाधान का कार्यान्वयन है जो इसे ठीक करता है। EndWithoutNewLine चेक सब कुछ के लिए बेकार हैं लेकिन अंतिम रूप से पढ़ा जाता है, लेकिन समग्र कार्य की तुलना में तुच्छ समय के अनुसार होना चाहिए।

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
अच्छी पकड़। सुनिश्चित नहीं हैं कि आपने केवल स्वीकृत उत्तर को संपादित क्यों नहीं किया और टिप्पणी में एक टिप्पणी करें। ज्यादातर लोग इसे दूर नहीं पढ़ेंगे।
रयान

@ रेयान, 90 साल के उत्थान के साथ 4 साल पुराने स्वीकृत उत्तर को संपादित करना ठीक नहीं समझा।
DMulligan

@AFinkelstein, मुझे लगता है कि यही वह जगह है जो इस साइट को इतना महान बनाती है, कि आप शीर्ष वोट किए गए उत्तर को संपादित कर सकते हैं
सेबस्टियन

3
यह समाधान कैरिज रिटर्न (\ r) और कैरिज रिटर्न का पालन नहीं करता है, इसके बाद एक लाइनफीड (\ r \ n)
साइमन ब्रान्डहोफ़ - सोनारसोर्स

@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
कोड में त्रुटियाँ हैं। सरल, लेकिन बहुत धीमा ... मेरे जवाब को नीचे (ऊपर) देखने की कोशिश करें।
अर्नेस्टस ग्रूडिस

12

यदि किसी फ़ाइल में फ़ाइल के अंत में कोई नई रेखा नहीं थी, तो यह विधि गणना () से ऊपर के उत्तर ने मुझे पंक्ति में शामिल कर दिया - यह फ़ाइल की अंतिम पंक्ति को गिनने में विफल रहा।

यह विधि मेरे लिए बेहतर काम करती है:

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 का उपयोग करें, उस स्थिति में आपके पास लंबे डेटाटाइप का उपयोग करने के लिए लचीलापन है cnt
सैयद अकील आशिक

[जानकारी] PMD विफलता: xx: 19 नियम: EmptyWhileStmt प्राथमिकता: 3 इन कथनों से खाली रहने से बचें।
छोड़े एलीट

8

मुझे पता है कि यह एक पुराना सवाल है, लेकिन स्वीकृत समाधान काफी मेल नहीं खाता कि मुझे क्या करने की आवश्यकता है। इसलिए, मैंने विभिन्न लाइन टर्मिनेटर (केवल लाइन फीड के बजाय) को स्वीकार करने और एक निर्दिष्ट चरित्र एन्कोडिंग (आईएसओ-8859- एन के बजाय) का उपयोग करने के लिए इसे परिष्कृत किया। । सभी एक विधि में (उपयुक्त के रूप में रिफ्लेक्टर):

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% धीमा है (हालांकि जावा में समय परीक्षण बेहद अविश्वसनीय हैं)।


8

मैंने लाइनों की गणना के लिए उपरोक्त तरीकों का परीक्षण किया और यहां मेरे सिस्टम पर परीक्षण किए गए विभिन्न तरीकों के लिए मेरी टिप्पणियों हैं

फ़ाइल का आकार: 1.6 जीबी तरीके:

  1. स्कैनर का उपयोग करना : 35 के लगभग
  2. बफ़रडर का उपयोग करना : 5s लगभग
  3. जावा 8 : 5 एस लगभग का उपयोग करना
  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और लाइनों की संख्या भी गलत है
aw-think

मैंने 32-बिट मशीन पर परीक्षण किया। हो सकता है कि 64-बिट पर अलग-अलग परिणाम होंगे .. और यह 10 गुना या उससे अधिक का अंतर था जितना मुझे याद है। क्या आप कहीं पंक्ति को गिनने के लिए पाठ पोस्ट कर सकते हैं? सुविधा के लिए लाइन ब्रेक देखने के लिए आप नोटपैड 2 का उपयोग कर सकते हैं।
अर्नेस्टस ग्रूडिस

वह अंतर हो सकता है।
aw-

यदि आप प्रदर्शन के बारे में परवाह करते हैं, तो आपको BufferedInputStreamतब उपयोग नहीं करना चाहिए जब आप किसी भी तरह से अपने बफर में पढ़ने जा रहे हों। इसके अलावा, भले ही आपकी विधि में थोड़ा सा प्रदर्शन लाभ हो सकता है, यह लचीलापन खो देता है, क्योंकि यह एकमात्र \rलाइन टर्मिनेटर (पुराने MacOS) का समर्थन नहीं करता है और हर एन्कोडिंग का समर्थन नहीं करता है।
होल्गर

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: newlines की गिनती की विधि ठीक है, लेकिन उन फाइलों पर गैर-सहज परिणाम देता है जहां अंतिम पंक्ति एक नई रेखा के साथ समाप्त नहीं होती है।

और @ 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

जावा कोड के भीतर से प्रोसेस क्लास का उपयोग कैसे करें? और फिर कमांड का आउटपुट पढ़ना।

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

यदि आपके पास कोई अनुक्रमणिका संरचना नहीं है, तो आपको संपूर्ण फ़ाइल के पढ़ने के आसपास नहीं मिलेगा। लेकिन आप इसे लाइन से लाइन पढ़ने से बचने के लिए इसे ऑप्टिमाइज़ कर सकते हैं और सभी लाइन टर्मिनेटर से मिलान करने के लिए एक रेगेक्स का उपयोग कर सकते हैं।


एक स्वच्छ विचार की तरह लगता है। किसी ने कोशिश की और इसके लिए एक rexxp है?
.कोडजावफोरफूड

1
मुझे संदेह है कि यह इतना अच्छा विचार है: इसे एक बार में पूरी फाइल पढ़ने की आवश्यकता होगी (मार्टिंस इस से बचता है) और इस तरह के उपयोग के लिए रीगेक्स ओवरकिल (और धीमी) हैं (फिक्स्ड चार (एस) की सरल खोज)।
फीलोहो

@ क्या: क्या के बारे में / \ n /? @PhiLo: रेगेक्स एक्ज़ीक्यूटर्स उच्च-ट्यून किए गए प्रदर्शन मशीन हैं। रीड-एवरीथिंग-इन-मेमोरी कैविएट को छोड़कर, मुझे नहीं लगता कि मैन्युअल कार्यान्वयन तेजी से हो सकता है।
डेविड श्मिट

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

यूनिक्स-आधारित सिस्टम wcपर, कमांड-लाइन पर कमांड का उपयोग करें ।


@ImmH, आपका दूसरा सुझाव वर्तमान निर्देशिका में प्रविष्टियों की संख्या को गिनाता है। इरादा नहीं था क्या? (या ओपी द्वारा पूछा गया)
आर्किटिपल पॉल

@IMMH: यह है कि wc वैसे भी क्या करता है (फ़ाइल को पढ़ना, लाइन-एंड की गिनती करना)।
फीलोहो

@PhiLho आपको लाइनों को गिनने के लिए -l स्विच का उपयोग करना होगा। (क्या तुम नहीं? - यह एक समय हो गया है)
इयान होल्डर

@ पाओल - आप बेशक 100% सही हैं। मेरा एकमात्र बचाव यह है कि मैंने अपनी कॉफी से पहले पोस्ट किया। मैं अब एक बटन की तरह तेज हूं। : डी
इयान होल्डर

0

केवल यह जानने का तरीका है कि फ़ाइल में कितनी लाइनें हैं, उन्हें गिनना है। आप निश्चित रूप से अपने डेटा से एक मीट्रिक बना सकते हैं, जो आपको एक पंक्ति की औसत लंबाई देता है और फिर फ़ाइल का आकार प्राप्त करता है और इसे avg के साथ विभाजित करता है। लंबाई लेकिन यह सही नहीं होगा।


1
दिलचस्प बात यह है कि आप चाहे जो भी कमांड लाइन टूल का उपयोग कर रहे हों, वे सभी समान रूप से केवल आंतरिक रूप से करते हैं। लाइनों की संख्या का पता लगाने के लिए कोई जादुई तरीका नहीं है, उन्हें हाथ से गिना जाना चाहिए। यकीन है कि इसे मेटाडेटा के रूप में सहेजा जा सकता है, लेकिन यह एक पूरी कहानी है ...
एस्को

0

EOF पर कोई नई रेखा ('\ n') वर्ण वाली मल्टी लाइन फ़ाइलों के लिए सर्वश्रेष्ठ अनुकूलित कोड।

/**
 * 
 * @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 से वापसी अंतर है। आपको अधिकतम पंक्तियों को संसाधित करने के लिए लंबे प्रकार के डेटा की आवश्यकता होती है।


14
एक intतक, लगभग 2 बिलियन का मान रखा जा सकता है। यदि आप 2 बिलियन से अधिक लाइनों वाली फाइल लोड कर रहे हैं, तो आपको ओवरफ्लो की समस्या है। उस ने कहा, यदि आप दो अरब से अधिक लाइनों के साथ एक अनएन्डेक्सित पाठ फ़ाइल लोड कर रहे हैं, तो आपको शायद अन्य समस्याएं हैं।
एडम नॉरबर्ग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.