दिलचस्प पोस्ट
एंड्रॉइड: सभी गतिविधियों पर नेविगेशन ड्रॉवर Django क्वेरी – आईडी बनाम पीके जांचें कि डाउनलोड पूरा हो गया है या नहीं 1 9 80 से कंप्यूटिंग में महत्वपूर्ण नए आविष्कार एक स्थान के साथ कई स्थान बदलने के लिए Regex PostgreSQL में टाइमस्टैम्प से तारीख निकालें (yyyy / mm / dd) पीएसपी असिंक्रोनस सॉकेट्स का उपयोग कर सकते हैं? डेबियन पर संस्करण 2.13 से 2.15 तक glibc को अपग्रेड कैसे करें? IOS: popViewController अनपेक्षित व्यवहार जावा में एक ऑब्जेक्ट कब पहुंचा जा सकता है? IOS में UITextField में पासवर्ड सत्यापन एक ही समय में आईओएस पिंच स्केल और दो फ़िंगर रोटेट करें लाइन के बाद फ़ाइल का हिस्सा कैसे प्राप्त करें जो कि grep अभिव्यक्ति से मेल खाता है? (पहला मैच) IPhone ऐप में इंटरनेट और स्टोर से ऑडियो / वीडियो फ़ाइलों को कैसे डाउनलोड करें? सी में मुद्रा या धन का प्रतिनिधित्व कैसे करें

अजगर में फ़ाइल की अंतिम x लाइनों को खोजने का सबसे कारगर तरीका

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

s = "foo" last_bit = fileObj.readlines()[-10:] for line in last_bit: if line == s: print "FOUND" 

Solutions Collecting From Web of "अजगर में फ़ाइल की अंतिम x लाइनों को खोजने का सबसे कारगर तरीका"

 # Tail from __future__ import with_statement find_str = "FIREFOX" # String to find fname = "g:/autoIt/ActiveWin.log_2" # File to check with open(fname, "r") as f: f.seek (0, 2) # Seek @ EOF fsize = f.tell() # Get Size f.seek (max (fsize-1024, 0), 0) # Set pos @ last n chars lines = f.readlines() # Read to end lines = lines[-10:] # Get last 10 lines # This returns True if any line is exactly find_str + "\n" print find_str + "\n" in lines # If you're searching for a substring for line in lines: if find_str in line: print True break 

यहां एक उत्तर है जैसे MizardX है, लेकिन सबसे खराब स्थिति में द्विघात समय लेने की अपनी स्पष्ट समस्या के बिना, वर्किंग स्ट्रिंग को बार-बार न्यूलाइन के रूप में सहेजा जा रहा है क्योंकि विखंडन जोड़ा जाता है।

सक्रिय समाधान के मुकाबले (जो कि द्विआधारी भी लगता है), यह खाली फ़ाइल को उड़ा नहीं देता, और प्रत्येक के बजाय प्रत्येक प्रति ब्लॉक की खोज करता है

'पूंछ' की उत्पत्ति के मुकाबले यह आत्मनिहित है। (लेकिन यदि आपके पास है तो 'पूंछ' सबसे अच्छा है।)

अंत में कुछ केबी को हथियाने की अपेक्षा करते हुए और यह पर्याप्त है, यह किसी भी लाइन की लंबाई के लिए काम करता है

 import os def reversed_lines(file): "Generate the lines of file in reverse order." part = '' for block in reversed_blocks(file): for c in reversed(block): if c == '\n' and part: yield part[::-1] part = '' part += c if part: yield part[::-1] def reversed_blocks(file, blocksize=4096): "Generate blocks of file's contents in reverse order." file.seek(0, os.SEEK_END) here = file.tell() while 0 < here: delta = min(blocksize, here) here -= delta file.seek(here, os.SEEK_SET) yield file.read(delta) 

इसे अनुरोध के रूप में उपयोग करने के लिए:

 from itertools import islice def check_last_10_lines(file, key): for line in islice(reversed_lines(file), 10): if line.rstrip('\n') == key: print 'FOUND' break 

संपादित करें: बदल गया मानचित्र () to itertools.imap () में सिर () संपादित करें 2: सरलीकृत उलट किए गए ब्लॉक () 3 संपादित करें: नई लाइनों के लिए पूंछ को बचाने से बचें 4 संपादित करें: reversed_lines rewrote () क्योंकि str.splitlines () एक अंतिम '\ n' की अनदेखी करते हैं, जैसा कि ब्रायन बी ने देखा (धन्यवाद)।

ध्यान दें कि बहुत पुराने पायथन संस्करणों में स्ट्रिंग कन्टेनटेनेशन यहां एक लूप में द्विघात समय लगेगा। कम से कम पिछले कुछ वर्षों से CPython इस समस्या को स्वचालित रूप से टालता है।

यदि आप किसी POSIX सिस्टम पर पायथन चला रहे हैं, तो आप पिछले कुछ लाइनों को प्राप्त करने के लिए 'पूंछ -10' का उपयोग कर सकते हैं। पिछले 10 लाइनों को प्राप्त करने के लिए यह अपना पायथन कोड लिखने से तेज़ हो सकता है फ़ाइल को सीधे खोलने के बजाय, 'पूंछ -10 फ़ाइलनाम' से एक पाइप खोलें। यदि आप कुछ लॉग आउटपुट हैं (उदाहरण के लिए, आप जानते हैं कि कभी भी बहुत लंबी लाइनें नहीं हैं जो सैकड़ों या हजारों वर्ण लंबे होते हैं) तो एक 'अंतिम 2KB पढ़ें पटल पढ़ें' का उपयोग करके ठीक होगा।

मुझे लगता है कि आखिरी 2 KB या फ़ाइल को पढ़ना चाहिए, आपको यह सुनिश्चित करना चाहिए कि आपको 10 लाइन मिलें, और बहुत अधिक संसाधन नहीं होनी चाहिए

 file_handle = open("somefile") file_size = file_handle.tell() file_handle.seek(max(file_size - 2*1024, 0)) # this will get rid of trailing newlines, unlike readlines() last_10 = file_handle.read().splitlines()[-10:] assert len(last_10) == 10, "Only read %d lines" % len(last_10) 

यहाँ एक संस्करण है जो बहुत कुशल लगता है mmap का उपयोग कर रहा है। बड़ा प्लस यह है कि mmap लिए फ़ाइल को स्वचालित रूप से स्मृति पेजिंग की आवश्यकताओं के लिए संभालता है

 import os from mmap import mmap def lastn(filename, n): # open the file and mmap it f = open(filename, 'r+') m = mmap(f.fileno(), os.path.getsize(f.name)) nlcount = 0 i = m.size() - 1 if m[i] == '\n': n += 1 while nlcount < n and i > 0: if m[i] == '\n': nlcount += 1 i -= 1 if i > 0: i += 2 return m[i:].splitlines() target = "target string" print [l for l in lastn('somefile', 10) if l == target] 

मुझे लगता है मुझे मनू गर्ग से इस ब्लॉग पोस्ट से कोड का अनुकूलन करना याद है जब मुझे कुछ ऐसा करना था।

यदि आप एक यूनिक्स बॉक्स पर हैं, तो os.popen("tail -10 " + filepath).readlines() शायद सबसे तेज़ तरीका होगा। अन्यथा, यह इस बात पर निर्भर करता है कि आप इसे कैसे मजबूत करना चाहते हैं। अब तक प्रस्तावित तरीकों सभी नीचे गिर जाएगी, एक तरह से या किसी अन्य सबसे आम मामले में मजबूती और गति के लिए आप संभवतः लॉगरिदमिक खोज की तरह कुछ चाहते हैं: फ़ाइल शून्य से 1000 अक्षरों के अंत में जाने के लिए फ़ाइल का उपयोग करें, इसे पढ़िए, इसमें कितनी रेखाएं हैं, फिर EOF घटाएं 3000 वर्णों के लिए , 2000 अक्षरों में पढ़ा, लाइनों की गणना करें, फिर ईओफ़ शून्य से 7000, 4000 अक्षरों में पढ़ा, पंक्तियों की गणना करें, आदि। जब तक आपके पास जरूरत के अनुसार कई लाइनें नहीं हैं लेकिन अगर आप यह सुनिश्चित करने के लिए जानते हैं कि यह हमेशा समझदार रेखा लंबाई वाली फाइलों पर चलने वाला है, तो आपको इसकी ज़रूरत नहीं होगी।

आपको यूनिक्स tail कमांड के लिए स्रोत कोड में कुछ प्रेरणा मिल सकती है।

मैं उस समस्या में चली गई, बड़ी syslog फाइलों के आखिरी घंटे को पार्स कर रहा था, और इस समारोह को सक्रियता की नुस्खा साइट से इस्तेमाल किया … ( http://code.activestate.com/recipes/439045/ )

 !/usr/bin/env python # -*-mode: python; coding: iso-8859-1 -*- # # Copyright (c) Peter Astrand <astrand@cendio.se> import os import string class BackwardsReader: """Read a file line by line, backwards""" BLKSIZE = 4096 def readline(self): while 1: newline_pos = string.rfind(self.buf, "\n") pos = self.file.tell() if newline_pos != -1: # Found a newline line = self.buf[newline_pos+1:] self.buf = self.buf[:newline_pos] if pos != 0 or newline_pos != 0 or self.trailing_newline: line += "\n" return line else: if pos == 0: # Start-of-file return "" else: # Need to fill buffer toread = min(self.BLKSIZE, pos) self.file.seek(-toread, 1) self.buf = self.file.read(toread) + self.buf self.file.seek(-toread, 1) if pos - toread == 0: self.buf = "\n" + self.buf def __init__(self, file): self.file = file self.buf = "" self.file.seek(-1, 2) self.trailing_newline = 0 lastchar = self.file.read(1) if lastchar == "\n": self.trailing_newline = 1 self.file.seek(-1, 2) # Example usage br = BackwardsReader(open('bar')) while 1: line = br.readline() if not line: break print repr(line) 

यह वास्तव में अच्छी तरह से काम करता है और बहुत अधिक कुशल होता है, जैसे fileObj.readlines () [- 10:], जो अजगर को पूरी फाइल मेमोरी में पढ़ता है और फिर उसमें से अंतिम 10 लाइनों को बंद कर देता है

आप 1000 बाइट्स के भाग को पढ़ सकते हैं या बफ़र में फ़ाइल के अंत से जब तक आपके पास 10 लाइन नहीं हो।

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

 lines = 0 chunk_size = 1024 f = file('filename') f.seek(0, 2) f.seek(f.tell() - chunk_size) while True: s = f.read(chunk_size) lines += s.count('\n') if lines > NUM_OF_LINES: break f.seek(f.tell() - chunk_size*2) 

अब फाइल readlines() को चलाने के लिए अच्छी स्थिति में है आप पहली बार पढ़ते हुए स्ट्रिंग्स को कैश कर सकते हैं, ताकि फ़ाइल के एक ही हिस्से को दो बार पढ़ने को खत्म कर सकें।

मैंने mmap का उपयोग करने के लिए महाक के सुझाव लिया और एक संस्करण लिखा जो rfind का उपयोग करता है:

 from mmap import mmap import sys def reverse_file(f): mm = mmap(f.fileno(), 0) nl = mm.size() - 1 prev_nl = mm.size() while nl > -1: nl = mm.rfind('\n', 0, nl) yield mm[nl + 1:prev_nl] prev_nl = nl + 1 def main(): # Example usage with open('test.txt', 'r+') as infile: for line in reverse_file(infile): sys.stdout.write(line) 

फ़ाइल के अंतिम कुछ केएस पढ़ें, और केवल पिछले 10 लौटने के लिए लाइनों में विभाजित है।

यह काफी संभावना नहीं है कि उस खंड की शुरुआत लाइन सीमा पर आती है, लेकिन आप पहले लाइनों को वैसे भी त्याग देंगे।

निजी तौर पर मुझे शेल के बाहर तोड़ना और पूंछ -10 को कॉल करने के लिए प्रोजेक्ट लोड करना होगा। लेकिन तब मैं वास्तव में एक पायथन प्रोग्रामर नहीं हूं;)

सबसे पहले, एक समारोह जो एक सूची देता है:

 def lastNLines(file, N=10, chunksize=1024): lines = None file.seek(0,2) # go to eof size = file.tell() for pos in xrange(chunksize,size-1,chunksize): # read a chunk file.seek(pos,2) chunk = file.read(chunksize) if lines is None: # first time lines = chunk.splitlines() else: # other times, update the 'first' line with # the new data, and re-split lines[0:1] = (chunk + lines[0]).splitlines() if len(lines) > N: return lines[-N:] file.seek(0) chunk = file.read(size-pos) lines[0:1] = (chunk + lines[0]).splitlines() return lines[-N:] 

दूसरा, एक फ़ंक्शन जो रिवर्स ऑर्डर में लाइनों पर चलता है:

 def iter_lines_reversed(file, chunksize=1024): file.seek(0,2) size = file.tell() last_line = "" for pos in xrange(chunksize,size-1,chunksize): # read a chunk file.seek(pos,2) chunk = file.read(chunksize) + last_line # split into lines lines = chunk.splitlines() last_line = lines[0] # iterate in reverse order for index,line in enumerate(reversed(lines)): if index > 0: yield line # handle the remaining data at the beginning of the file file.seek(0) chunk = file.read(size-pos) + last_line lines = chunk.splitlines() for line in reversed(lines): yield line 

आपके उदाहरण के लिए:

 s = "foo" for index, line in enumerate(iter_lines_reversed(fileObj)): if line == s: print "FOUND" break elif index+1 >= 10: break 

संपादित करें: अब फ़ाइल आकार स्वचालित रूप से मिलता है
संपादन 2: अब केवल 10 लाइनों के लिए पुनरावृत्त।

यह समाधान फ़ाइल को केवल एक बार पढ़ाएगा, लेकिन दो फाइल ऑब्जेक्ट पॉइंटर्स का प्रयोग करके अंतिम एन लाइनों को बिना पुनः बिना पढ़ने के लिए प्राप्त कर सकता है:

 def getLastLines (path, n): # return the las N lines from the file indicated in path fp = open(path) for i in range(n): line = fp.readline() if line == '': return [] back = open(path) for each in fp: back.readline() result = [] for line in back: result.append(line[:-1]) return result s = "foo" last_bit = getLastLines(r'C:\Documents and Settings\ricardo.m.reyes\My Documents\desarrollo\tail.py', 10) for line in last_bit: if line == s: print "FOUND" 

शायद यह उपयोगी हो सकता है:

 import os.path path = 'path_to_file' os.system('tail -n1 ' + path)