2012-03-09 10 views
14

फाइल मैं एक बहुत साधारण स्क्रिप्ट अभी कि enumerate() का उपयोग कर एक पाठ फ़ाइल में लाइनों में गिना जाता है:(अजगर) एक बहुत बड़ा (> 10GB) में लाइनों की गिनती जितनी जल्दी संभव

i = 0 
f = open("C:/Users/guest/Desktop/file.log", "r") 
for i, line in enumerate(f): 
     pass 
print i + 1 
f.close() 

यह लगभग 3 लेता है और ~ 30 मिलियन लाइनों के साथ 15 जीबी लॉग फ़ाइल के माध्यम से जाने के लिए आधा मिनट। यह बहुत अच्छा होगा अगर मैं इसे दो मिनट या उससे कम के नीचे प्राप्त कर सकूं, क्योंकि ये दैनिक लॉग हैं और हम मासिक विश्लेषण करना चाहते हैं, इसलिए कोड को ~ 15 जीबी के 30 लॉग संसाधित करना होगा - संभवत: डेढ़ घंटे से अधिक , और हम सर्वर पर & मेमोरी लोड को कम करना चाहते हैं।

मैं भी एक अच्छा सन्निकटन/आकलन विधि के लिए समझौता होगा, लेकिन यह लगभग 4 sig अंजीर सही होने की जरूरत है ...

धन्यवाद!

+3

आम तौर पर फ़ाइल को बाइनरी डेटा के रूप में समझने के लिए तेज़ होगा, इसे उचित रूप से आकार वाले हिस्सों में कहें (कहें, एक समय में 4 केबी), और प्रत्येक चंक में \ n' अक्षरों को गिनें। – aroth

+4

यह आपके निष्पक्ष समाधान से बेहतर प्रदर्शन नहीं कर रहा है, लेकिन आपके पास जो कुछ है, उसे लिखने के लिए पाइथोनिक तरीका केवल 'खुले (fname) के साथ होगा: प्रिंट राशि (एफ में लाइन के लिए 1) ' – wim

+1

अरोथ: धन्यवाद टिप, मुझे उसमें देखना चाहिए। विम: बढ़िया, धन्यवाद, यह बहुत छोटा है ... – Adrienne

उत्तर

17

Ignacio's answer सही है, लेकिन यदि आपके पास 32 बिट प्रक्रिया है तो विफल हो सकता है।

लेकिन हो सकता है कि फ़ाइल ब्लॉक-वार को पढ़ने के लिए उपयोगी हो और फिर प्रत्येक ब्लॉक में \n वर्णों को गिनें।

def blocks(files, size=65536): 
    while True: 
     b = files.read(size) 
     if not b: break 
     yield b 

with open("file", "r") as f: 
    print sum(bl.count("\n") for bl in blocks(f)) 

आपका काम करेगा।

ध्यान दें कि मैं फ़ाइल को बाइनरी के रूप में नहीं खोलता, इसलिए \r\n को \n में परिवर्तित कर दिया जाएगा, जिससे गिनती अधिक विश्वसनीय हो जाएगी।

+1

बस एक डेटा बिंदु के रूप में, इस दृष्टिकोण का उपयोग करते हुए एक सेकंड के नीचे निष्क्रिय दृष्टिकोण का उपयोग करके लगभग 51 एमबी की एक बड़ी फ़ाइल का एक मिनट लगभग एक मिनट से चला गया। –

+3

@MKatz अब क्या, "एक बड़ी फाइल" या "लगभग 51 एमबी की फाइल"?;-) – glglgl

+0

यह समाधान अंतिम लाइन को याद कर सकता है लेकिन इससे कोई बड़ी फ़ाइल के लिए कोई फर्क नहीं पड़ता। –

5

mmap फ़ाइल, और न्यूलाइन को गिनें।

6

मैं अपने एक सा अनुचित जानते हैं, लेकिन आप यदि आपके खिड़कियों पर Coreutils

+0

मेरा समाधान केवल 1 एम 37 वास्तविक समय लेता है। –

+1

यह बहुत तेज है –

+0

ऐसा लगता है कि आपको 'int (subprocess.check_output ("/ usr/bin/wc -l cred", shell = True) .split() [0])' python3 के लिए ' – ZN13

0

एक तेजी से, 1 लाइन समाधान है इस

int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0]) 

कर सकता है:

sum((1 for i in open(file_path, 'rb'))) 

यह काम करना चाहिए मनमानी आकार की फाइलों पर।

1

मैं जीएल के जवाब का विस्तार करने और तेजी से गिनती के लिए बहु पायथन मॉड्यूल का उपयोग कर उसकी/उसके कोड को चलाने चाहते हैं:

def blocks(f, cut, size=64*1024): # 65536 
    start, chunk =cut 
    iter=0 
    read_size=int(size) 
    _break =False 
    while not _break: 
     if _break: break 
     if f.tell()+size>start+chunk: 
      read_size=int(start+chunk- f.tell()) 
      _break=True 
     b = f.read(read_size) 
     iter +=1 
     if not b: break 
     yield b 


def get_chunk_line_count(data): 
    fn, chunk_id, cut = data 
    start, chunk =cut 
    cnt =0 
    last_bl=None 

    with open(fn, "r") as f: 
     if 0: 
      f.seek(start) 
      bl = f.read(chunk) 
      cnt= bl.count('\n') 
     else: 
      f.seek(start) 
      for i, bl in enumerate(blocks(f,cut)): 
       cnt += bl.count('\n') 
       last_bl=bl 

     if not last_bl.endswith('\n'): 
      cnt -=1 

     return cnt 
.... 
pool = multiprocessing.Pool(processes=pool_size, 
          initializer=start_process, 
          ) 
pool_outputs = pool.map(get_chunk_line_count, inputs) 
pool.close() # no more tasks 
pool.join() 

यह गिनती प्रदर्शन 20 परतों में सुधार होगा। मैंने इसे script पर लपेट लिया और इसे गीथब में डाल दिया।

संबंधित मुद्दे