파이썬을 사용하여 파일에서 한 번에 두 줄을 읽는 방법
텍스트 파일을 구문 분석하는 파이썬 스크립트를 코딩하고 있습니다. 이 텍스트 파일의 형식은 파일의 각 요소가 두 줄을 사용하는 것과 같으며 편의를 위해 구문 분석 전에 두 줄을 모두 읽고 싶습니다. 파이썬으로 할 수 있습니까?
나는 다음과 같은 것을 원합니다.
f = open(filename, "r")
for line in f:
line1 = line
line2 = f.readline()
f.close
그러나 이것은 다음과 같이 말합니다.
ValueError : 반복 및 읽기 메서드를 혼합하면 데이터가 손실됩니다.
관련 :
여기에 비슷한 질문이 있습니다 . 반복과 readline을 혼합 할 수 없으므로 둘 중 하나를 사용해야합니다.
while True:
line1 = f.readline()
line2 = f.readline()
if not line2: break # EOF
...
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
실제로 동일한 반복자 f가 두 번 공급됩니다. 그러나 결국 일어나는 것은 next(f)
첫 번째 인수에서 호출 된 다음 두 번째 인수에서 호출 된다는 것 입니다. next()
동일한 기본 반복자에서 호출 되기 때문에 연속적인 라인이 생성됩니다. 이것은 전체 파일을 읽는 것과는 매우 다릅니다. 실제로 반복자를 사용하는 목적은 정확히 전체 파일을 읽는 것을 피하는 것입니다.
따라서 솔루션이 원하는대로 작동한다고 믿습니다. for 루프에서 파일을 한 번만 읽습니다.
이를 입증하기 위해 zip_longest 솔루션과 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
는 메모리를 훨씬 적게 사용 하기 때문에 전체 파일을 한 번에 읽지 않는다고 결론을 내리는 것이 안전하다고 생각합니다.
사용 next()
예
with open("file") as f:
for line in f:
print(line)
nextline = next(f)
print("next line", nextline)
....
나는 ghostdog74 와 비슷한 방식으로 진행할 것입니다 .
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
.
이건 어때요? 문제가있는 사람은 누구나
with open('file_name') as f:
for line1, line2 in zip(f, f):
print(line1, line2)
짝수 및 홀수 길이 파일에 대해 작동합니다. 일치하지 않는 마지막 줄을 무시합니다.
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()
대용량 파일이있는 경우 올바른 방법이 아닙니다. readlines ()를 사용하여 메모리의 모든 파일을로드하고 있습니다. 한 번은 각 줄 시작의 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
file_name = 'your_file_name' file_open = open (파일 _ 이름, 'r') def 핸들러 (line_one, line_two) : 인쇄 (1 행, 2 행) file_open 동안 : 시험: 하나 = file_open.next () two = file_open.next () 핸들러 (하나, 둘) except (StopIteration) : file_open.close () 단절
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
My idea is to create a generator that reads two lines from the file at a time, and returns this as a 2-tuple, This means you can then iterate over the results.
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
If you have an odd number of lines, it won't work perfectly, but this should give you a good outline.
I have worked on a similar problem last month. I tried a while loop with f.readline() as well as f.readlines(). My data file is not huge, so I finally chose f.readlines(), which gives me more control of the index, otherwise I have to use f.seek() to move back and forth the file pointer.
My case is more complicated than OP. Because my data file is more flexible on how many lines to be parsed each time, so I have to check a few conditions before I can parse the data.
Another problem I found out about f.seek() is that it doesn't handle utf-8 very well when I use codecs.open('', 'r', 'utf-8'), (not exactly sure about the culprit, eventually I gave up this approach.)
Simple little reader. It will pull lines in pairs of two and return them as a tuple as you iterate over the object. You can close it manually or it will close itself when it falls out of scope.
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
f = open(filename, "r")
for line in f:
line1 = line
f.next()
f.close
Right now, you can read file every two line. If you like you can also check the f status before f.next()
If the file is of reasonable size, another approach that uses list-comprehension to read the entire file into a list of 2-tuples, is this:
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))
This Python code will print the first two lines:
import linecache
filename = "ooxx.txt"
print(linecache.getline(filename,2))
'Development Tip' 카테고리의 다른 글
SQL Server IIF와 CASE (0) | 2020.10.26 |
---|---|
로그 스케일 및 사용자 지정 나누기가있는 히스토그램 (0) | 2020.10.26 |
일부 패턴을 제외하고 grep하는 방법? (0) | 2020.10.26 |
임시 변수가 내 프로그램을 느리게합니까? (0) | 2020.10.26 |
중괄호가있는 Javascript (ES6) const (0) | 2020.10.26 |