मैं अजगर का उपयोग करते हुए एक समय में एक फ़ाइल से दो लाइनें कैसे पढ़ता हूं


82

मैं एक अजगर स्क्रिप्ट को कोड कर रहा हूं जो एक टेक्स्ट फाइल को पार्स करता है। इस पाठ फ़ाइल का प्रारूप ऐसा है कि फ़ाइल में प्रत्येक तत्व दो पंक्तियों का उपयोग करता है और सुविधा के लिए मैं पार्स करने से पहले दोनों पंक्तियों को पढ़ना चाहूंगा। क्या यह पायथन में हो सकता है?

मैं कुछ इस तरह करना चाहूंगा:

f = open(filename, "r")
for line in f:
    line1 = line
    line2 = f.readline()

f.close

लेकिन यह कहते हुए टूट जाता है कि:

ValueError: पुनरावृति को मिक्स करके पढ़ने के तरीके डेटा खो देंगे

सम्बंधित:


8
बदलें f.readline () से f.next () और आप सभी सेट हैं।
— पॉल

कुछ और उत्तरों के लिए stackoverflow.com/questions/1528711/reading-lines-2-at-a-time देखें ।
— फोसियन

@Paul क्या यह f.next () अभी भी मान्य है? मुझे यह त्रुटि मिल रही है AttrorError: '_io.TextIOWrapper' ऑब्जेक्ट में कोई विशेषता नहीं 'अगला' है
— SKR

1
पायथन 3 पर @SKR आपको next(f)इसके बजाय करना होगा।
— बोरिस

जवाबों:


50

इसी तरह का सवाल यहाँ । आप पुनरावृत्ति और रीडलाइन को नहीं मिला सकते हैं, इसलिए आपको एक या दूसरे का उपयोग करने की आवश्यकता है।

while True:
    line1 = f.readline()
    line2 = f.readline()
    if not line2: break  # EOF
    ...

48
import itertools
with open('a') as f:
    for line1,line2 in itertools.zip_longest(*[f]*2):
        print(line1,line2)

itertools.zip_longest() एक पुनरावृत्ति देता है, तो यह अच्छी तरह से काम करेगा भले ही फ़ाइल अरबों लाइनों की हो।

यदि विषम संख्या में लाइनें हैं, तो इसके line2लिए सेट हैNone अंतिम पुनरावृत्ति पर गया है।

Python2 पर आपको izip_longestइसके बजाय उपयोग करने की आवश्यकता है ।


टिप्पणियों में, यह पूछा गया है कि क्या यह समाधान पहले पूरी फ़ाइल पढ़ता है, और फिर दूसरी बार फ़ाइल पर पुनरावृत्ति करता है। मेरा मानना ​​है कि ऐसा नहीं है। with open('a') as fलाइन एक फ़ाइल हैंडल को खोलता है, लेकिन फ़ाइल को पढ़ने नहीं है। fएक इटरेटर है, इसलिए अनुरोध किए जाने तक इसकी सामग्री नहीं पढ़ी जाती है। zip_longestतर्क के रूप में पुनरावृत्तियों लेता है, और एक पुनरावृत्ति देता है।

zip_longestवास्तव में एक ही पुनरावृत्त खिलाया जाता है, च, दो बार। लेकिन जो समाप्त होता है वह next(f)यह है कि पहले तर्क पर और फिर दूसरे तर्क पर कहा जाता है। जबसेnext() एक ही अंतर्निहित पुनरावृत्ति पर बुलाया जा रहा है, क्रमिक लाइनों का उत्पादन किया जाता है। यह पूरी फाइल में पढ़ने की तुलना में बहुत अलग है। वास्तव में पुनरावृत्तियों का उपयोग करने का उद्देश्य पूरी फ़ाइल में पढ़ने से बचने के लिए ठीक है।

इसलिए मेरा मानना ​​है कि समाधान वांछित के रूप में काम करता है - फ़ाइल केवल एक बार फॉर-लूप द्वारा पढ़ी जाती है।

इसे पुष्ट करने के लिए, मैंने zip_longest solution बनाम a solution का उपयोग करके भाग लिया f.readlines()। मैंने input()स्क्रिप्ट को रोकने के लिए अंत में एक को रखा , और ps axuwप्रत्येक पर भाग गया:

% ps axuw | grep zip_longest_method.py

unutbu 11119 2.2 0.2 4520 2712 pts/0 S+ 21:14 0:00 python /home/unutbu/pybin/zip_longest_method.py bigfile

% ps axuw | grep readlines_method.py

unutbu 11317 6.5 8.8 93908 91680 pts/0 S+ 21:16 0:00 python /home/unutbu/pybin/readlines_method.py bigfile

readlinesस्पष्ट रूप से एक ही बार में पूरी फ़ाइल में पढ़ता है। चूंकि zip_longest_methodबहुत कम मेमोरी का उपयोग करता है, मुझे लगता है कि यह निष्कर्ष निकालना सुरक्षित है कि यह एक बार में पूरी फ़ाइल में नहीं पढ़ रहा है।


6
मुझे पसंद है (*[f]*2)क्योंकि यह दिखाता है कि आप किसी भी आकार की चांस प्राप्त कर सकते हैं जिसे आप केवल संख्या बदलकर चाहते हैं (इसलिए मैं इसे बदलने के लिए उत्तर को संपादित नहीं करूंगा), लेकिन इस मामले (f, f)में टाइप करना आसान है।
— स्टीव लोस

यदि आप linesइसके बजाय का उपयोग करते हैं, line1, line2तो आपको एक बार में लाइनों 2को पढ़ने के लिए केवल एक नंबर ( ) बदलना होगा n।
— jfs

27

का उपयोग करें next(), जैसे

with open("file") as f:
    for line in f:
        print(line)
        nextline = next(f)
        print("next line", nextline)
        ....

1
जैसा कि RedGlyph इस उत्तर के अपने संस्करण में बताता है, एक विषम संख्या में लाइनों का परिणाम होगा StopIteration।
— drevicko

2
अगला () अब अपवाद से बचने के लिए एक डिफ़ॉल्ट तर्क का समर्थन करता है:nextline = next(f,None)
— gerardw

11

मैं घोस्टडॉग74 के समान ही आगे बढ़ूंगा , केवल बाहर की कोशिश और कुछ संशोधनों के साथ:

try:
    with open(filename) as f:
        for line1 in f:
            line2 = f.next()
            # process line1 and line2 here
except StopIteration:
    print "(End)" # do whatever you need to do with line1 alone

यह कोड को सरल और अभी तक मजबूत रखता है। का उपयोग करते हुएwith फ़ाइल बंद कर देता है, तो कुछ और ही होता है, या सिर्फ संसाधनों एक बार आप इसे समाप्त और पाश से बाहर निकलने की है बंद कर देता है।

ध्यान दें कि सक्षम सुविधा के withसाथ 2.6, या 2.5 की आवश्यकता है with_statement।


8

कैसे इस बारे में, किसी को भी इसके साथ एक समस्या देख रहा है

with open('file_name') as f:
    for line1, line2 in zip(f, f):
        print(line1, line2)

1
यदि आपकी फ़ाइल में लाइनों की विषम संख्या है, तो यह अंतिम पंक्ति को छोड़ देगा। अच्छी बात यह है कि आप इसे एक बार में 3 पंक्तियों को पढ़ने के लिए बढ़ा सकते हैं for l1, l2, l3 in zip(f, f, f):; यदि लाइनों की संख्या 3 से विभाज्य नहीं है तो फिर से, अंतिम 1 या 2 लाइनों को छोड़ दिया जाएगा
— बोरिस

4

सम और विषम-लंबाई फ़ाइलों के लिए काम करता है। यह केवल बेजोड़ अंतिम रेखा को नजरअंदाज करता है।

f=file("file")

lines = f.readlines()
for even, odd in zip(lines[0::2], lines[1::2]):
    print "even : ", even
    print "odd : ", odd
    print "end cycle"
f.close()

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

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

import string
import re

class FileReader:
    """ 
    Similar to file class, but allows to access smoothly the lines 
    as when using readlines(), with no memory payload, going back and forth,
    finding regexps and so on.
    """
    def __init__(self,filename): # fold>>
        self.__file=file(filename,"r")
        self.__currentPos=-1
        # get file length
        self.__file.seek(0,0)
        counter=0
        line=self.__file.readline()
        while line != '':
            counter = counter + 1
            line=self.__file.readline()
        self.__length = counter
        # collect an index of filedescriptor positions against
        # the line number, to enhance search
        self.__file.seek(0,0)
        self.__lineToFseek = []

        while True:
            cur=self.__file.tell()
            line=self.__file.readline()
            # if it's not null the cur is valid for
            # identifying a line, so store
            self.__lineToFseek.append(cur)
            if line == '':
                break
    # <<fold
    def __len__(self): # fold>>
        """
        member function for the operator len()
        returns the file length
        FIXME: better get it once when opening file
        """
        return self.__length
        # <<fold
    def __getitem__(self,key): # fold>>
        """ 
        gives the "key" line. The syntax is

        import FileReader
        f=FileReader.FileReader("a_file")
        line=f[2]

        to get the second line from the file. The internal
        pointer is set to the key line
        """

        mylen = self.__len__()
        if key < 0:
            self.__currentPos = -1
            return ''
        elif key > mylen:
            self.__currentPos = mylen
            return ''

        self.__file.seek(self.__lineToFseek[key],0)
        counter=0
        line = self.__file.readline()
        self.__currentPos = key
        return line
        # <<fold
    def next(self): # fold>>
        if self.isAtEOF():
            raise StopIteration
        return self.readline()
    # <<fold
    def __iter__(self): # fold>>
        return self
    # <<fold
    def readline(self): # fold>>
        """
        read a line forward from the current cursor position.
        returns the line or an empty string when at EOF
        """
        return self.__getitem__(self.__currentPos+1)
        # <<fold
    def readbackline(self): # fold>>
        """
        read a line backward from the current cursor position.
        returns the line or an empty string when at Beginning of
        file.
        """
        return self.__getitem__(self.__currentPos-1)
        # <<fold
    def currentLine(self): # fold>>
        """
        gives the line at the current cursor position
        """
        return self.__getitem__(self.__currentPos)
        # <<fold
    def currentPos(self): # fold>>
        """ 
        return the current position (line) in the file
        or -1 if the cursor is at the beginning of the file
        or len(self) if it's at the end of file
        """
        return self.__currentPos
        # <<fold
    def toBOF(self): # fold>>
        """
        go to beginning of file
        """
        self.__getitem__(-1)
        # <<fold
    def toEOF(self): # fold>>
        """
        go to end of file
        """
        self.__getitem__(self.__len__())
        # <<fold
    def toPos(self,key): # fold>>
        """
        go to the specified line
        """
        self.__getitem__(key)
        # <<fold
    def isAtEOF(self): # fold>>
        return self.__currentPos == self.__len__()
        # <<fold
    def isAtBOF(self): # fold>>
        return self.__currentPos == -1
        # <<fold
    def isAtPos(self,key): # fold>>
        return self.__currentPos == key
        # <<fold

    def findString(self, thestring, count=1, backward=0): # fold>>
        """
        find the count occurrence of the string str in the file
        and return the line catched. The internal cursor is placed
        at the same line.
        backward is the searching flow.
        For example, to search for the first occurrence of "hello
        starting from the beginning of the file do:

        import FileReader
        f=FileReader.FileReader("a_file")
        f.toBOF()
        f.findString("hello",1,0)

        To search the second occurrence string from the end of the
        file in backward movement do:

        f.toEOF()
        f.findString("hello",2,1)

        to search the first occurrence from a given (or current) position
        say line 150, going forward in the file 

        f.toPos(150)
        f.findString("hello",1,0)

        return the string where the occurrence is found, or an empty string
        if nothing is found. The internal counter is placed at the corresponding
        line number, if the string was found. In other case, it's set at BOF
        if the search was backward, and at EOF if the search was forward.

        NB: the current line is never evaluated. This is a feature, since
        we can so traverse occurrences with a

        line=f.findString("hello")
        while line == '':
            line.findString("hello")

        instead of playing with a readline every time to skip the current
        line.
        """
        internalcounter=1
        if count < 1:
            count = 1
        while 1:
            if backward == 0:
                line=self.readline()
            else:
                line=self.readbackline()

            if line == '':
                return ''
            if string.find(line,thestring) != -1 :
                if count == internalcounter:
                    return line
                else:
                    internalcounter = internalcounter + 1
                    # <<fold
    def findRegexp(self, theregexp, count=1, backward=0): # fold>>
        """
        find the count occurrence of the regexp in the file
        and return the line catched. The internal cursor is placed
        at the same line.
        backward is the searching flow.
        You need to pass a regexp string as theregexp.
        returns a tuple. The fist element is the matched line. The subsequent elements
        contains the matched groups, if any.
        If no match returns None
        """
        rx=re.compile(theregexp)
        internalcounter=1
        if count < 1:
            count = 1
        while 1:
            if backward == 0:
                line=self.readline()
            else:
                line=self.readbackline()

            if line == '':
                return None
            m=rx.search(line)
            if m != None :
                if count == internalcounter:
                    return (line,)+m.groups()
                else:
                    internalcounter = internalcounter + 1
    # <<fold
    def skipLines(self,key): # fold>>
        """
        skip a given number of lines. Key can be negative to skip
        backward. Return the last line read.
        Please note that skipLines(1) is equivalent to readline()
        skipLines(-1) is equivalent to readbackline() and skipLines(0)
        is equivalent to currentLine()
        """
        return self.__getitem__(self.__currentPos+key)
    # <<fold
    def occurrences(self,thestring,backward=0): # fold>>
        """
        count how many occurrences of str are found from the current
        position (current line excluded... see skipLines()) to the
        begin (or end) of file.
        returns a list of positions where each occurrence is found,
        in the same order found reading the file.
        Leaves unaltered the cursor position.
        """
        curpos=self.currentPos()
        list = []
        line = self.findString(thestring,1,backward)
        while line != '':
            list.append(self.currentPos())
            line = self.findString(thestring,1,backward)
        self.toPos(curpos)
        return list
        # <<fold
    def close(self): # fold>>
        self.__file.close()
    # <<fold

आप इसके बजाय विशेष रूप से बड़ी फ़ाइलों के लिए itertools.izip () का उपयोग करना चाह सकते हैं!
— RedGlyph

Izip के साथ भी, सूची को इस तरह से खिसकाना कि सब कुछ स्मृति में खींच लेगा।
— स्टीव लोस

दरअसल readlines()कॉल हर चीज को मेमोरी में भी खींच लेगा।
— स्टीव लोस

मुझे आपकी कक्षा पसंद नहीं है। आप फ़ाइल को इनिशियलाइज़ करते समय पूरी फ़ाइल पर दो बार पुनरावृत्ति कर रहे हैं। छोटी लाइनों वाली बड़ी फ़ाइलों के लिए सहेजी गई मेमोरी ज्यादा नहीं है।
— जॉर्ज स्कोली 15

@ पाठ: हाँ, दुख की बात है कि पर्याप्त है। लेकिन ज़िप टपल्स की पूरी सूची (जब तक कि यह पायथन 3 नहीं है) बनाकर स्मृति में एक अतिरिक्त परत जोड़ देगा, जहां izip एक बार में ट्यूपल्स उत्पन्न करेगा। मुझे लगता है कि आपका क्या मतलब है, लेकिन मैं अपनी पिछली टिप्पणी को वैसे भी स्पष्ट कर दूंगा :-)
— RedGlyph

3
file_name = 'your_file_name'
file_open = open (file_name, 'r')

डीएफ़ हैंडलर (लाइन_ऑन, लाइन_ट्वो):
    प्रिंट (लाइन_ऑन, लाइन_ट्वो)

फ़ाइल के दौरान:
    प्रयत्न:
        एक = file_open.next ()
        दो = file_open.next () 
        हैंडलर (एक, दो)
    को छोड़कर (StopIteration):
        file_open.close ()
        टूटना

1
while file_open:यह while True:इस मामले में बराबर होने के कारण भ्रामक है ।
— बजे

जो जानबूझकर किया जाता है, हालांकि मैं मानता हूं कि यह 'सही है जबकि' यह दर्शाता है कि आपको लूप से बाहर निकलने के लिए ब्रेक की जरूरत है। मैंने इसे नहीं करने के लिए चुना क्योंकि मुझे विश्वास है (फिर से तर्कपूर्ण) कि यह इस तरह से अच्छे को पढ़ता है, इस पर कोई संदेह नहीं है कि फ़ाइल को खुले रहने की आवश्यकता है और उस समय के साथ इसका क्या करना है। हालांकि मैं ज्यादातर समय अपने लिए ही 'सच्चा' करता हूँ।
— मार्टिन पी। हेलविग

2
def readnumlines(file, num=2):
    f = iter(file)
    while True:
        lines = [None] * num
        for i in range(num):
            try:
                lines[i] = f.next()
            except StopIteration: # EOF or not enough lines available
                return
        yield lines

# use like this
f = open("thefile.txt", "r")
for line1, line2 in readnumlines(f):
    # do something with line1 and line2

# or
for line1, line2, line3, ..., lineN in readnumlines(f, N):
    # do something with N lines

1

मेरा विचार एक जनरेटर बनाने का है जो एक बार में फ़ाइल से दो लाइनें पढ़ता है, और इसे 2-ट्यूपल के रूप में लौटाता है, इसका मतलब है कि आप फिर परिणामों पर पुनरावृति कर सकते हैं।

from cStringIO import StringIO

def read_2_lines(src):   
    while True:
        line1 = src.readline()
        if not line1: break
        line2 = src.readline()
        if not line2: break
        yield (line1, line2)


data = StringIO("line1\nline2\nline3\nline4\n")
for read in read_2_lines(data):
    print read

यदि आपके पास विषम संख्या है, तो यह पूरी तरह से काम नहीं करेगा, लेकिन इससे आपको एक अच्छी रूपरेखा मिलनी चाहिए।


1

मैंने पिछले महीने इसी तरह की समस्या पर काम किया है। मैंने f.readline () के साथ-साथ f.readlines () के साथ थोड़ी देर की कोशिश की। मेरी डेटा फ़ाइल बहुत बड़ी नहीं है, इसलिए मैंने अंततः f.readlines () को चुना, जिससे मुझे सूचकांक का अधिक नियंत्रण प्राप्त हुआ, अन्यथा मुझे फ़ाइल पॉइंटर को आगे और पीछे ले जाने के लिए f.seek () का उपयोग करना पड़ता है।

ओपी की तुलना में मेरा मामला अधिक जटिल है। क्योंकि मेरी डेटा फ़ाइल अधिक लचीली होती है कि हर बार कितनी लाइनों को पार्स किया जाना है, इसलिए मुझे डेटा पार्स करने से पहले कुछ शर्तों की जांच करनी होगी।

एक और समस्या जो मुझे f.seek () के बारे में मिली, वह यह है कि यह utf-8 को बहुत अच्छी तरह से हैंडल नहीं करता है, जब मैं codecs.open ('', 'r', 'utf-8') का उपयोग करता हूं, (इस बारे में निश्चित रूप से निश्चित नहीं है अपराधी, आखिरकार मैंने इस दृष्टिकोण को छोड़ दिया।)


1

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

class doublereader:
    def __init__(self,filename):
        self.f = open(filename, 'r')
    def __iter__(self):
        return self
    def next(self):
        return self.f.next(), self.f.next()
    def close(self):
        if not self.f.closed:
            self.f.close()
    def __del__(self):
        self.close()

#example usage one
r = doublereader(r"C:\file.txt")
for a, h in r:
    print "x:%s\ny:%s" % (a,h)
r.close()

#example usage two
for x,y in doublereader(r"C:\file.txt"):
    print "x:%s\ny:%s" % (x,y)
#closes itself as soon as the loop goes out of scope

1
f = open(filename, "r")
for line in f:
    line1 = line
    f.next()

f.close

अभी, आप हर दो लाइन में फ़ाइल पढ़ सकते हैं। आप चाहें तो पहले f स्टेटस भी चेक कर सकते हैंf.next()


0

फ़ाइल उचित आकार का है, तो एक और दृष्टिकोण का उपयोग करता है सूची-समझ एक में पूरी फ़ाइल को पढ़ने के लिए 2-tuples की सूची , यह है:

filaname = '/path/to/file/name'

with open(filename, 'r') as f:
    list_of_2tuples = [ (line,f.readline()) for line in f ]

for (line1,line2) in list_of_2tuples: # Work with them in pairs.
    print('%s :: %s', (line1,line2))

-2

यह पायथन कोड पहली दो पंक्तियों को मुद्रित करेगा:

import linecache  
filename = "ooxx.txt"  
print(linecache.getline(filename,2))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.