पायथन में सस्ते में बड़ी फ़ाइल की लाइन काउंट कैसे प्राप्त करें?


1009

मुझे अजगर में एक बड़ी फ़ाइल (सैकड़ों लाइनों की सैकड़ों) की एक पंक्ति गणना प्राप्त करने की आवश्यकता है। स्मृति- और समय-वार दोनों में सबसे कुशल तरीका क्या है?

फिलहाल मैं करता हूं:

def file_len(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

क्या कोई बेहतर करना संभव है?


7
क्या आपको सटीक लाइन काउंट की आवश्यकता है या एक सन्निकटन पर्याप्त होगा?
पिको

43
मैं लूप के लिए i = -1 जोड़ूंगा, क्योंकि यह कोड खाली फाइलों के लिए काम नहीं करता है।
मकीक सवाई

12
@Legend: मुझे यकीन है कि पिको सोच रहा है, फ़ाइल का आकार (तलाश (0,2) या इक्विव के साथ) प्राप्त करें, अनुमानित रेखा लंबाई से विभाजित करें। आप औसत लाइन की लंबाई का अनुमान लगाने के लिए शुरुआत में कुछ लाइनें पढ़ सकते थे।
ऐनी

32
enumerate(f, 1)और खाई i + 1?
इयान मैकिनन

4
@IanMackinnon खाली फाइलों के लिए काम करता है, लेकिन आपको फॉर-लूप से पहले मुझे 0 से इनिशियलाइज़ करना होगा ।
scai

जवाबों:


356

आपको इससे बेहतर कोई नहीं मिल सकता।

आखिरकार, किसी भी समाधान को पूरी फ़ाइल को पढ़ना होगा, यह पता लगाना होगा कि \nआपके पास कितने हैं, और उस परिणाम को वापस करें।

क्या आपके पास ऐसा करने का एक बेहतर तरीका है जो पूरी फ़ाइल को पढ़े बिना है? निश्चित नहीं ... सबसे अच्छा समाधान हमेशा I / O- बाउंड होगा, सबसे अच्छा आप यह कर सकते हैं कि आप अनावश्यक मेमोरी का उपयोग न करें, लेकिन ऐसा लगता है कि आपने कवर किया है।


7
वास्तव में, यहां तक ​​कि WC फ़ाइल के माध्यम से पढ़ रहा है, लेकिन सी में और यह शायद बहुत अनुकूलित है।
लाफुर वेज

6
जहां तक ​​मैं समझता हूं कि पायथन फाइल IO C के माध्यम से भी की जाती है। docs.python.org/library/stdtypes.html#file-objects
Tomalak

9
@ टोमलाक यह एक लाल हेरिंग है। जबकि अजगर और wc एक ही syscalls जारी कर सकता है, जबकि अजगर के पास overcode है जो wc के पास नहीं है।
22

4
आप नमूने द्वारा एक पंक्ति गणना का अनुमान लगा सकते हैं। यह हजारों गुना तेज हो सकता है। देखें: documentroot.com/2011/02/…
एरिक एरोनिटी

4
अन्य उत्तरों से लगता है कि यह स्पष्ट जवाब गलत है, और इसलिए इसे स्वीकार किए जाने के बजाय हटा दिया जाना चाहिए।
स्किप्पी ले ग्रैंड गौरौ

623

एक पंक्ति, शायद बहुत तेज:

num_lines = sum(1 for line in open('myfile.txt'))

8
इसके योग के समान (१ क्रम) प्रत्येक रेखा १. >>> [१ श्रेणी में रेखा के लिए (१०)] [१, १, १, १, १, १, १, १, १, १] है। >>> राशि (1 रेंज में लाइन के लिए (10)) 10 >>>
जेम्स सपैम

4
num_lines = sum (1 ओपन में लाइन के लिए ('myfile.txt') अगर लाइन .rstrip ()) खाली लाइनों को फ़िल्टर करने के लिए
Honghe.Wu

61
जब हम एक फ़ाइल खोलते हैं, तो क्या हम सभी तत्वों पर पुनरावृति करने के बाद स्वतः बंद हो जाएंगे? क्या it पास ’() होना आवश्यक है? मुझे लगता है कि हम इस संक्षिप्त विवरण में 'ओपन के साथ' () का उपयोग नहीं कर सकते हैं, है ना?
मन्नगिया

16
@ मेनगैगिया आप सही हैं, बेहतर होगा कि 'ओपन (फ़ाइलनाम) के साथ' का उपयोग करें, यह सुनिश्चित करने के लिए कि फ़ाइल बंद होने पर किया जाता है, और इससे भी बेहतर यह कोशिश करने वाले ब्लॉक के भीतर कर रहा है, जहां और IOError अपवाद को फेंक दिया जाता है यदि फ़ाइल को खोला नहीं जा सकता।
बोल्ट्जमनब्रेन

17
नोट करने के लिए एक और बात: यह ~ ०.०४-०.०५ सेकंड एक ३०० हजार लाइन टेक्स्ट फाइल पर दी गई मूल समस्या की तुलना में धीमी है
andrew

202

मुझे विश्वास है कि एक मेमोरी मैप की गई फ़ाइल सबसे तेज़ समाधान होगी। मैंने चार कार्यों की कोशिश की: ओपी द्वारा पोस्ट किया गया फ़ंक्शन ( opcount); फ़ाइल में लाइनों पर एक साधारण पुनरावृत्ति ( simplecount); मेमोरी-मैपेड (एमएमएपी) ( mapcount) के साथ रीडलाइन ; और Mykola Kharechko ( bufcount) द्वारा प्रस्तुत बफर रीड समाधान ।

मैंने प्रत्येक फ़ंक्शन को पांच बार चलाया, और 1.2 मिलियन-लाइन टेक्स्ट फ़ाइल के लिए औसत रन-टाइम की गणना की।

विंडोज एक्सपी, पायथन 2.5, 2 जीबी रैम, 2 गीगाहर्ट्ज एएमडी प्रोसेसर

यहाँ मेरे परिणाम हैं:

mapcount : 0.465599966049
simplecount : 0.756399965286
bufcount : 0.546800041199
opcount : 0.718600034714

संपादित करें : पायथन 2.6 के लिए नंबर:

mapcount : 0.471799945831
simplecount : 0.634400033951
bufcount : 0.468800067902
opcount : 0.602999973297

इसलिए विंडोज / पायथन 2.6 के लिए बफर रीड स्ट्रैटेजी सबसे तेज़ लगती है

यहाँ कोड है:

from __future__ import with_statement
import time
import mmap
import random
from collections import defaultdict

def mapcount(filename):
    f = open(filename, "r+")
    buf = mmap.mmap(f.fileno(), 0)
    lines = 0
    readline = buf.readline
    while readline():
        lines += 1
    return lines

def simplecount(filename):
    lines = 0
    for line in open(filename):
        lines += 1
    return lines

def bufcount(filename):
    f = open(filename)                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    return lines

def opcount(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1


counts = defaultdict(list)

for i in range(5):
    for func in [mapcount, simplecount, bufcount, opcount]:
        start_time = time.time()
        assert func("big_file.txt") == 1209138
        counts[func].append(time.time() - start_time)

for key, vals in counts.items():
    print key.__name__, ":", sum(vals) / float(len(vals))

1
संपूर्ण मेमोरी-मैप की गई फ़ाइल मेमोरी में लोड नहीं होती है। आपको एक वर्चुअल मेमोरी स्पेस मिलता है, जिसे ओएस आवश्यकतानुसार RAM में और बाहर स्वैप करता है। यहां बताया गया है कि वे विंडोज पर कैसे संभाले हुए हैं: msdn.microsoft.com/en-us/library/ms810613.aspx
रयान गिंस्ट्रोम

1
क्षमा करें, यहां मेमोरी-मैप की गई फ़ाइलों पर अधिक सामान्य संदर्भ है: en.wikipedia.org/wiki/Memory-mapped_file और वोट के लिए धन्यवाद। :)
रयान गिंस्ट्रोम

1
भले ही यह सिर्फ एक वर्चुअल मेमोरी हो, लेकिन यह वास्तव में इस दृष्टिकोण को सीमित करता है और इसलिए यह बड़ी फ़ाइलों के लिए काम नहीं करेगा। मैं इसे ~ 10 जीबी से अधिक के साथ ~ 1.2 जीबी फ़ाइल के साथ कोशिश की है। लाइनें (जैसा कि wc -l के साथ प्राप्त किया गया है) और बस एक WindowsError मिली: [त्रुटि 8] इस कमांड को संसाधित करने के लिए पर्याप्त भंडारण उपलब्ध नहीं है। बेशक, यह एक किनारे का मामला है।
साइलेंटगॉस्ट

6
वास्तविक समय डेटा के लिए +1। क्या हमें पता है कि 1024 * 1024 का बफर साइज़ इष्टतम है, या बेहतर है?
किव

28
ऐसा लगता है कि wccount()यह सबसे तेज़ gist.github.com/0ac760859e614cd03652 है
jfs

133

मुझे इसी तरह के सवाल पर पोस्ट करना था जब तक कि मेरा प्रतिष्ठा स्कोर थोड़ा उछल नहीं गया (धन्यवाद जिसने भी मुझे टक्कर दी!)।

ये सभी समाधान इस रन को एक तरह से अनदेखा कर देते हैं, जैसे कि अनफर्ड (कच्चे) इंटरफ़ेस का उपयोग करके, बायट्रीज़ का उपयोग करके, और अपनी स्वयं की बफरिंग करके। (यह केवल पायथन 3 में लागू होता है। पायथन 2 में, कच्चा इंटरफ़ेस डिफ़ॉल्ट रूप से उपयोग किया जा सकता है या नहीं भी हो सकता है, लेकिन पायथन 3 में, आप यूनिकोड में डिफ़ॉल्ट होंगे।)

टाइमिंग टूल के संशोधित संस्करण का उपयोग करना, मेरा मानना ​​है कि निम्न कोड किसी भी समाधान की तुलना में तेज़ (और मामूली रूप से अधिक पायथोनिक) है:

def rawcount(filename):
    f = open(filename, 'rb')
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.raw.read

    buf = read_f(buf_size)
    while buf:
        lines += buf.count(b'\n')
        buf = read_f(buf_size)

    return lines

एक अलग जनरेटर फ़ंक्शन का उपयोग करते हुए, यह तेजी से एक फ्रिज चलाता है:

def _make_gen(reader):
    b = reader(1024 * 1024)
    while b:
        yield b
        b = reader(1024*1024)

def rawgencount(filename):
    f = open(filename, 'rb')
    f_gen = _make_gen(f.raw.read)
    return sum( buf.count(b'\n') for buf in f_gen )

इसे पूरी तरह से जेनरेटरों के साथ पूरी तरह से किया जा सकता है, जिसमें इटर्लूल का उपयोग किया जा सकता है, लेकिन यह देखने में काफी अजीब लगता है:

from itertools import (takewhile,repeat)

def rawincount(filename):
    f = open(filename, 'rb')
    bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))
    return sum( buf.count(b'\n') for buf in bufgen )

यहाँ मेरे समय हैं:

function      average, s  min, s   ratio
rawincount        0.0043  0.0041   1.00
rawgencount       0.0044  0.0042   1.01
rawcount          0.0048  0.0045   1.09
bufcount          0.008   0.0068   1.64
wccount           0.01    0.0097   2.35
itercount         0.014   0.014    3.41
opcount           0.02    0.02     4.83
kylecount         0.021   0.021    5.05
simplecount       0.022   0.022    5.25
mapcount          0.037   0.031    7.46

20
मैं 100 जीबी + फाइलों के साथ काम कर रहा हूं, और आपके रॉजेनकाउंट्स एकमात्र संभव समाधान है जो मैंने अब तक देखा है। धन्यवाद!
soungalo

1
है wccountउपप्रक्रिया खोल के लिए इस तालिका में wcउपकरण?
एंथ्रोपिक 18

1
यह एक और टिप्पणी में पाया, मुझे लगता है कि यह तो gist.github.com/zed/0ac760859e614cd03652 है
एंथ्रोपिक

3
धन्यवाद @ माइकल-बेकन, यह वास्तव में एक अच्छा समाधान है। आप संयोजन के बजाय का rawincountउपयोग करके समाधान को कम अजीब देख सकते हैं और । bufgen = iter(partial(f.raw.read, 1024*1024), b'')takewhilerepeat
पीटर एच।

1
ओह, आंशिक समारोह, हाँ, यह एक अच्छा सा tweak है। इसके अलावा, मैंने यह मान लिया कि 1024 * 1024 दुभाषिए द्वारा विलीन हो जाएगा और इसे एक स्थिरांक के रूप में माना जाएगा लेकिन यह दस्तावेजीकरण नहीं था।
माइकल बेकन

90

आप एक सबप्रोसेस निष्पादित कर सकते हैं और चला सकते हैं wc -l filename

import subprocess

def file_len(fname):
    p = subprocess.Popen(['wc', '-l', fname], stdout=subprocess.PIPE, 
                                              stderr=subprocess.PIPE)
    result, err = p.communicate()
    if p.returncode != 0:
        raise IOError(err)
    return int(result.strip().split()[0])

6
इसका विंडोज़ संस्करण क्या होगा?
साइलेंटगॉस्ट

1
आप इस एसओ से संबंधित प्रश्न का उल्लेख कर सकते हैं। stackoverflow.com/questions/247234/…
Waलाफुर वेज

7
वास्तव में, मेरे मामले में (मैक ओएस एक्स) यह "फ़ाइल में एक्स के लिए" (...) "लाइनों की संख्या की गणना के लिए 0.13s बनाम 0.5s लेता है, बनाम 1.0s बार-बार कॉल करता है str.find या mmap.find को । (जिस फाइल का मैंने परीक्षण किया,
उसमें

1
उस पर शेल को शामिल करने की आवश्यकता नहीं है। संपादित उत्तर और जोड़ा उदाहरण कोड;
nosklo

2
प्लेटफ़ॉर्म नहीं है।
ई-इंफो128

42

यहाँ मशीन / कोर के पार लाइन की गिनती को वितरित करने के लिए मल्टीप्रोसेसिंग लाइब्रेरी का उपयोग करने के लिए एक अजगर कार्यक्रम है। मेरा परीक्षण 8 कोर विंडो 64 सर्वर का उपयोग करके 26 सेकंड से 7 सेकंड तक 20 मिलियन बिलियन फ़ाइल की गिनती में सुधार करता है। नोट: मेमोरी मैपिंग का उपयोग नहीं करने से चीजें बहुत धीमी हो जाती हैं।

import multiprocessing, sys, time, os, mmap
import logging, logging.handlers

def init_logger(pid):
    console_format = 'P{0} %(levelname)s %(message)s'.format(pid)
    logger = logging.getLogger()  # New logger at root level
    logger.setLevel( logging.INFO )
    logger.handlers.append( logging.StreamHandler() )
    logger.handlers[0].setFormatter( logging.Formatter( console_format, '%d/%m/%y %H:%M:%S' ) )

def getFileLineCount( queues, pid, processes, file1 ):
    init_logger(pid)
    logging.info( 'start' )

    physical_file = open(file1, "r")
    #  mmap.mmap(fileno, length[, tagname[, access[, offset]]]

    m1 = mmap.mmap( physical_file.fileno(), 0, access=mmap.ACCESS_READ )

    #work out file size to divide up line counting

    fSize = os.stat(file1).st_size
    chunk = (fSize / processes) + 1

    lines = 0

    #get where I start and stop
    _seedStart = chunk * (pid)
    _seekEnd = chunk * (pid+1)
    seekStart = int(_seedStart)
    seekEnd = int(_seekEnd)

    if seekEnd < int(_seekEnd + 1):
        seekEnd += 1

    if _seedStart < int(seekStart + 1):
        seekStart += 1

    if seekEnd > fSize:
        seekEnd = fSize

    #find where to start
    if pid > 0:
        m1.seek( seekStart )
        #read next line
        l1 = m1.readline()  # need to use readline with memory mapped files
        seekStart = m1.tell()

    #tell previous rank my seek start to make their seek end

    if pid > 0:
        queues[pid-1].put( seekStart )
    if pid < processes-1:
        seekEnd = queues[pid].get()

    m1.seek( seekStart )
    l1 = m1.readline()

    while len(l1) > 0:
        lines += 1
        l1 = m1.readline()
        if m1.tell() > seekEnd or len(l1) == 0:
            break

    logging.info( 'done' )
    # add up the results
    if pid == 0:
        for p in range(1,processes):
            lines += queues[0].get()
        queues[0].put(lines) # the total lines counted
    else:
        queues[0].put(lines)

    m1.close()
    physical_file.close()

if __name__ == '__main__':
    init_logger( 'main' )
    if len(sys.argv) > 1:
        file_name = sys.argv[1]
    else:
        logging.fatal( 'parameters required: file-name [processes]' )
        exit()

    t = time.time()
    processes = multiprocessing.cpu_count()
    if len(sys.argv) > 2:
        processes = int(sys.argv[2])
    queues=[] # a queue for each process
    for pid in range(processes):
        queues.append( multiprocessing.Queue() )
    jobs=[]
    prev_pipe = 0
    for pid in range(processes):
        p = multiprocessing.Process( target = getFileLineCount, args=(queues, pid, processes, file_name,) )
        p.start()
        jobs.append(p)

    jobs[0].join() #wait for counting to finish
    lines = queues[0].get()

    logging.info( 'finished {} Lines:{}'.format( time.time() - t, lines ) )

मुख्य मेमोरी की तुलना में फ़ाइलों के साथ यह कैसे काम करता है? उदाहरण के लिए 4GB रैम और 2 कोर के साथ एक सिस्टम पर 20GB की फाइल
ब्रायन मिंटन

अब परीक्षण करना मुश्किल है, लेकिन मुझे लगता है कि यह फ़ाइल को अंदर और बाहर कर देगा।
मार्तलाक

5
यह बहुत साफ कोड है। मुझे यह जानकर आश्चर्य हुआ कि कई प्रोसेसर का उपयोग करना तेज है। मुझे लगा कि IO अड़चन होगी। पुराने पायथन संस्करणों में, लाइन 21 को int () जैसे chunk = int ((fSize / प्रक्रियाओं)) + 1
Karl Henselin

क्या यह सभी फ़ाइल को मेमोरी में लोड करता है? क्या एक बड़ी आग के बारे में जहां आकार बड़ा है तो कंप्यूटर पर राम?
पेलोस

फ़ाइलों को वर्चुअल मेमोरी में मैप किया जाता है, इसलिए फ़ाइल का आकार और वास्तविक मेमोरी की मात्रा आमतौर पर प्रतिबंध नहीं है।
22

17

आधुनिक फ़ंक्शन का उपयोग करते हुए, इस उत्तर के समान एक-लाइन बैश समाधान subprocess.check_output:

def line_count(filename):
    return int(subprocess.check_output(['wc', '-l', filename]).split()[0])

इस उत्तर को लिनक्स / यूनिक्स उपयोगकर्ताओं के लिए इस थ्रेड में एक उच्च स्थान पर वोट किया जाना चाहिए। क्रॉस-प्लेटफ़ॉर्म समाधान में अधिकांश वरीयताओं के बावजूद, यह लिनक्स / यूनिक्स पर एक शानदार तरीका है। 184-मिलियन-लाइन सीएसवी फ़ाइल के लिए मुझे डेटा से नमूना करना होगा, यह सबसे अच्छा रनटाइम प्रदान करता है। अन्य शुद्ध अजगर समाधान औसतन 100+ सेकंड लेते हैं जबकि सबप्रोसेस कॉल wc -l~ 5 सेकंड लगते हैं।
शान डू

shell=Trueसुरक्षा के लिए बुरा है, इससे बचना बेहतर है।
एलेक्सी वाज़नोव

उचित बिंदु, संपादित
1 ''

15

मैं पायथन की फ़ाइल ऑब्जेक्ट विधि का उपयोग readlinesइस प्रकार करेगा:

with open(input_file) as foo:
    lines = len(foo.readlines())

यह फ़ाइल को खोलता है, फ़ाइल में लाइनों की एक सूची बनाता है, सूची की लंबाई की गणना करता है, इसे एक चर पर सहेजता है और फ़ाइल को फिर से बंद कर देता है।


6
हालांकि, यह पहले तरीकों में से एक है जो मन में आता है, यह शायद बहुत स्मृति कुशल नहीं है, खासकर अगर 10 जीबी तक की फाइलों में लाइनों की गिनती (जैसे मैं करता हूं), जो एक उल्लेखनीय नुकसान है।
१36

@TimeSheep क्या यह छोटी लाइनों के कई (कहते हैं, अरबों) फाइलों के लिए एक मुद्दा है या वे फाइलें जिनकी बहुत लंबी लाइनें हैं (जैसे, प्रति पंक्ति गीगाबाइट्स)?
रॉबर्ट

मेरे द्वारा पूछे जाने का कारण यह है कि ऐसा प्रतीत होता है कि संकलक को मध्यवर्ती सूची न बनाकर इसे दूर करने में सक्षम होना चाहिए।
रॉबर्ट

@dmityugov प्रति पायथन डॉक्स, xreadlines2.3 के बाद से पदावनत कर दिया गया है, क्योंकि यह सिर्फ एक पुनरावृत्त लौटाता है। for line in fileबताया गया प्रतिस्थापन है। देखें: docs.python.org/2/library/stdtypes.html#file.xreadlines
Kumba

12
def file_len(full_path):
  """ Count number of lines in a file."""
  f = open(full_path)
  nr_of_lines = sum(1 for line in f)
  f.close()
  return nr_of_lines

12

यहाँ मैं उपयोग करता हूँ, बहुत साफ लगता है:

import subprocess

def count_file_lines(file_path):
    """
    Counts the number of lines in a file using wc utility.
    :param file_path: path to file
    :return: int, no of lines
    """
    num = subprocess.check_output(['wc', '-l', file_path])
    num = num.split(' ')
    return int(num[0])

अद्यतन: यह शुद्ध रूप से शुद्ध अजगर का उपयोग करने की तुलना में तेज है, लेकिन स्मृति उपयोग की लागत पर। सबप्रोसेस, पैरेंट प्रोसेस के समान मेमोरी फुटप्रिंट के साथ एक नई प्रक्रिया को फोर्क करेगा जबकि यह आपकी कमांड को निष्पादित करता है।


1
एक साइड नोट के रूप में, यह विंडोज के पाठ्यक्रम पर काम नहीं करेगा।
ब्रैम वनरॉय

कोर बर्तन स्पष्ट रूप से खिड़कियों के लिए "wc" प्रदान करता है stackoverflow.com/questions/247234/… । यदि आप अपने कोड को प्रोडक्शंस में लिनक्स में चलाना समाप्त कर देंगे, तो आप अपने विंडोज़ बॉक्स में एक लिनक्स वीएम का उपयोग कर सकते हैं।
राडेक

या WSL, किसी भी VM पर अत्यधिक सलाह दी जाती है यदि इस तरह से सामान केवल एक चीज है जो आप करते हैं। :-)
ब्रैम वनरॉय

हाँ जो काम करता है। मैं विंडोज़ का आदमी नहीं हूँ, लेकिन गुगली करने से मैंने सीख लिया था WSL ​​= Linux के लिए Windows सबसिस्टम =)
radtek

3
python3.7: उपप्रकार वापसी बाइट्स, इसलिए कोड इस तरह दिखता है: int (subprocess.check_output (['wc', '-l', file_path])। decode ("utf-8-))। lstrip ()। विभाजन (") ") [0])
एलेक्सी अलेक्सिनका

11

यह सबसे तेज चीज है जिसे मैंने शुद्ध अजगर का उपयोग करके पाया है। बफर सेट करके आप जो भी मेमोरी चाहते हैं, उसका उपयोग कर सकते हैं, हालांकि 2 ** 16 मेरे कंप्यूटर पर एक मीठा स्थान है।

from functools import partial

buffer=2**16
with open(myfile) as f:
        print sum(x.count('\n') for x in iter(partial(f.read,buffer), ''))

मुझे यहाँ उत्तर मिला कि क्यों पठन की तुलना में C ++ में बहुत धीमी गति से लाइनें पढ़ रहा है? और इसे सिर्फ एक छोटा सा कहा। इसकी एक बहुत अच्छी समझ यह है कि कैसे लाइनों को जल्दी से गिनना है, हालांकि wc -lअभी भी लगभग 75% तेजी से कुछ और है।


9

मुझे इस संस्करण के साथ एक छोटा (4-8%) सुधार मिला जो एक निरंतर बफर का फिर से उपयोग करता है, इसलिए इसे किसी भी मेमोरी या जीसी ओवरहेड से बचना चाहिए:

lines = 0
buffer = bytearray(2048)
with open(filename) as f:
  while f.readinto(buffer) > 0:
      lines += buffer.count('\n')

आप बफ़र आकार के साथ चारों ओर खेल सकते हैं और शायद थोड़ा सुधार देखें।


अच्छा लगा। \ N में समाप्त न होने वाली फ़ाइलों का हिसाब रखने के लिए, बफर और बफर [-1] के बाहर लूप का 1 जोड़ें! = '' \ N '
riyusenshi

एक बग: अंतिम दौर में बफर साफ नहीं हो सकता है।
जे

क्या होगा अगर बफ़र्स के बीच में एक भाग \ के साथ समाप्त होता है और दूसरा भाग n से शुरू होता है? वहाँ एक नई लाइन याद आती है, मैं अंत में और प्रत्येक चंक की शुरुआत को संग्रहीत करने के लिए चर के लिए सबसे सरल होगा, लेकिन वह स्क्रिप्ट में अधिक समय जोड़ सकता है = (
pelos

9

काइल का जवाब

num_lines = sum(1 for line in open('my_file.txt'))

शायद सबसे अच्छा है, इसके लिए एक विकल्प है

num_lines =  len(open('my_file.txt').read().splitlines())

यहाँ दोनों के प्रदर्शन की तुलना है

In [20]: timeit sum(1 for line in open('Charts.ipynb'))
100000 loops, best of 3: 9.79 µs per loop

In [21]: timeit len(open('Charts.ipynb').read().splitlines())
100000 loops, best of 3: 12 µs per loop

9

एक पंक्ति समाधान:

import os
os.system("wc -l  filename")  

मेरा स्निपेट:

>>> os.system('wc -l *.txt')

0 bar.txt
1000 command.txt
3 test_file.txt
1003 total

अच्छा विचार, दुर्भाग्य से यह विंडोज पर काम नहीं करता है।
किम

3
यदि आप अजगर के सर्फर बनना चाहते हैं, तो खिड़कियों को अलविदा कहें। मुझे विश्वास करो कि आप मुझे एक दिन धन्यवाद देंगे।
एक्सोरसिस्ट

6
मैंने सिर्फ यह माना कि यह केवल खिड़कियों पर काम करेगा। मैं खुद एक लिनक्स / यूनिक्स स्टैक पर काम करना पसंद करता हूं, लेकिन सॉफ्टवेयर लिखने के दौरान आईएमएचओ को एक साइड इफेक्ट पर विचार करना चाहिए जो विभिन्न ओएस के तहत चलने पर एक प्रोग्राम हो सकता है। जैसा कि ओपी ने अपने मंच का उल्लेख नहीं किया है और अगर कोई भी इस समाधान को Google के माध्यम से पॉप करता है और इसे कॉपी करता है (एक विंडोज सिस्टम की सीमाओं से अनजान हो सकता है), तो मैं नोट जोड़ना चाहता था।
किम

आप os.system()किसी भी तरह से चर और बाद की प्रक्रिया के आउटपुट को नहीं बचा सकते ।
एक से

@AnSe आप सही हैं लेकिन सवाल यह नहीं पूछा गया है कि यह बचाता है या नहीं। मुझे लगता है कि आप संदर्भ को समझ रहे हैं।
एक्सोरसिस्ट

6

उपरोक्त विधियों को पूरा करने के लिए मैंने फाइलइनपुट मॉड्यूल के साथ एक प्रकार की कोशिश की:

import fileinput as fi   
def filecount(fname):
        for line in fi.input(fname):
            pass
        return fi.lineno()

और उपर्युक्त सभी तरीकों के लिए एक 60mil लाइनों की फाइल पास की:

mapcount : 6.1331050396
simplecount : 4.588793993
opcount : 4.42918205261
filecount : 43.2780818939
bufcount : 0.170812129974

यह मेरे लिए थोड़ा आश्चर्य की बात है कि फाइलइनपुट वह है जो अन्य सभी तरीकों की तुलना में बहुत खराब और खराब है ...


5

मेरे लिए यह संस्करण सबसे तेज़ होगा:

#!/usr/bin/env python

def main():
    f = open('filename')                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    print lines

if __name__ == '__main__':
    main()

कारण: लाइन से लाइन पढ़ने की तुलना में तेज़ होना और string.countबहुत तेज़ होना भी है


1
पर है क्या? कम से कम OSX / python2.5 पर ओपी का संस्करण अभी भी समयसीमा के अनुसार लगभग 10% तेज है।
डीएफ।

क्या होगा यदि अंतिम पंक्ति '\ n' में समाप्त नहीं होती है?
tzot

1
मुझे नहीं पता कि आपने इसका परीक्षण कैसे किया, dF, लेकिन मेरी मशीन पर यह किसी भी अन्य विकल्प की तुलना में ~ 2.5 गुना धीमा है।
साइलेंटगॉस्ट

34
आप कहते हैं कि यह सबसे तेज़ होगा और फिर यह बताएगा कि आपने इसका परीक्षण नहीं किया है। बहुत वैज्ञानिक एह नहीं? :)
--लाफुर वेज

नीचे रयान गिंस्ट्रोम द्वारा दिए गए समाधान और आँकड़े देखें। इसके अलावा जेएफ सेबेस्टियन की टिप्पणी और उसी उत्तर पर लिंक देखें।
शेरिलहोमन

5

यह कोड छोटा और स्पष्ट है। यह शायद सबसे अच्छा तरीका है:

num_lines = open('yourfile.ext').read().count('\n')

6
आपको फ़ाइल भी बंद करनी चाहिए।
रास

6
यह पूरी फाइल को मेमोरी में लोड कर देगा।
इवलिन

बड़ी फ़ाइलों पर प्रदर्शन की आवश्यकता होने पर सबसे अच्छा नहीं
mabraham

4

मैंने बफर केस को इस तरह संशोधित किया है:

def CountLines(filename):
    f = open(filename)
    try:
        lines = 1
        buf_size = 1024 * 1024
        read_f = f.read # loop optimization
        buf = read_f(buf_size)

        # Empty file
        if not buf:
            return 0

        while buf:
            lines += buf.count('\n')
            buf = read_f(buf_size)

        return lines
    finally:
        f.close()

अब खाली फाइलें और अंतिम पंक्ति (बिना \ n) को गिना जाता है।


शायद यह भी समझाएं (या कोड में टिप्पणी जोड़ें) आपने क्या बदला और क्या किया?)। लोगों को आपके कोड में कुछ और अधिक आसान (दिमाग में कोड को "पार्स" करने के बजाय) दे सकता है।
स्टाइलिश एक्स

लूप ऑप्टिमाइज़ेशन मुझे लगता है कि पायथन को read_f, python.org/doc/essays/list2str
लाल मटर

3

इस बारे में क्या

def file_len(fname):
  counts = itertools.count()
  with open(fname) as f: 
    for _ in f: counts.next()
  return counts.next()



3
def line_count(path):
    count = 0
    with open(path) as lines:
        for count, l in enumerate(lines, start=1):
            pass
    return count

3

यदि कोई लिनक्स में पायथन में लाइन की गिनती सस्ते में प्राप्त करना चाहता है, तो मैं इस विधि की सलाह देता हूं:

import os
print os.popen("wc -l file_path").readline().split()[0]

file_path अमूर्त फ़ाइल पथ या सापेक्ष पथ दोनों हो सकता है। आशा है कि यह मदद कर सकता है।


2

इस बारे में कैसा है?

import fileinput
import sys

counter=0
for line in fileinput.input([sys.argv[1]]):
    counter+=1

fileinput.close()
print counter

2

कैसे इस एक लाइनर के बारे में:

file_length = len(open('myfile.txt','r').read().split('\n'))

इस विधि का उपयोग करके 3900 लाइन फ़ाइल पर 0.003 सेकंड लेता है

def c():
  import time
  s = time.time()
  file_length = len(open('myfile.txt','r').read().split('\n'))
  print time.time() - s

2
def count_text_file_lines(path):
    with open(path, 'rt') as file:
        line_count = sum(1 for _line in file)
    return line_count

क्या आप कृपया बता सकते हैं कि क्या गलत है अगर आपको लगता है कि यह गलत है? इसने मेरे लिए काम किया। धन्यवाद!
जेसीलोआ

मुझे इस बात में दिलचस्पी होगी कि इस जवाब को क्यों नकारा गया। यह लाइनों द्वारा फाइल पर पुनरावृत्ति करता है और उन्हें ऊपर रखता है। मुझे यह पसंद है, यह छोटी और बात है, इसमें क्या गलत है?
citor

2

सरल विधि:

1)

>>> f = len(open("myfile.txt").readlines())
>>> f

430

2)

>>> f = open("myfile.txt").read().count('\n')
>>> f
430
>>>

3)

num_lines = len(list(open('myfile.txt')))

3
इस उदाहरण में फ़ाइल बंद नहीं है।
मैकिज एम

9
ओपी स्मृति को कुशल बनाना चाहता था। यह निश्चित रूप से नहीं है।
एंडी कार्लसन

1

फ़ाइल खोलने का परिणाम एक पुनरावृत्ति है, जिसे अनुक्रम में परिवर्तित किया जा सकता है, जिसकी लंबाई है:

with open(filename) as f:
   return len(list(f))

यह आपके स्पष्ट लूप की तुलना में अधिक संक्षिप्त है, और इससे बचा जाता है enumerate


10
जिसका अर्थ है कि 100 एमबी फ़ाइल को मेमोरी में पढ़ना होगा।
साइलेंटगॉस्ट

हां, अच्छी बात है, हालांकि मैं गति (स्मृति के विपरीत) अंतर के बारे में आश्चर्य करता हूं। ऐसा करने वाला संभवतया एक ऐसा इटरेटर बनाना संभव है, लेकिन मुझे लगता है कि यह आपके समाधान के बराबर होगा।
एंड्रयू जाफ

6
-1, यह सिर्फ मेमोरी नहीं है, बल्कि मेमोरी में लिस्ट बनाना है।
२१'०

0

आप os.pathनिम्नलिखित तरीके से मॉड्यूल का उपयोग कर सकते हैं :

import os
import subprocess
Number_lines = int( (subprocess.Popen( 'wc -l {0}'.format( Filename ), shell=True, stdout=subprocess.PIPE).stdout).readlines()[0].split()[0] )

, जहां Filenameफ़ाइल का पूर्ण पथ है।


1
इसका उत्तर क्या है os.path?
moi

0

यदि फ़ाइल मेमोरी में फिट हो सकती है, तो

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.