Безопасно ли смешивать readline () и итераторы строк при обработке файлов python? - PullRequest
17 голосов
/ 21 января 2011

Безопасно ли читать некоторые строки с readline(), а также использовать for line in file, и гарантированно ли используется та же самая позиция файла?

Обычно я хочу игнорировать первую строку (заголовки), поэтому я делаю это:

FI = open("myfile.txt")
FI.readline()             # disregard the first line
for line in FI:
    my_process(line)
FI.close()

Безопасно ли это, то есть гарантируется ли использование одной и той же переменной положения файла при переборе строк?

Ответы [ 3 ]

16 голосов
/ 21 января 2011

Нет, это небезопасно :

В результате использования буфера упреждающего чтения, комбинирования next () с другими методами файла (например, readline ()) не работает правильно.

Вы можете использовать next(), чтобы пропустить первую строку здесь.Вам также следует проверить значение StopIteration, которое будет поднято, если файл пуст.

with open('myfile.txt') as f:
    try:
        header = next(f)
    except StopIteration as e:
        print "File is empty"
    for line in f:
        # do stuff with line
4 голосов
/ 21 января 2011

Это хорошо работает в долгосрочной перспективе.Он игнорирует тот факт, что вы обрабатываете файл, и работает с любой последовательностью.Кроме того, наличие явного объекта-итератора (rdr), висящего вокруг, позволяет пропускать строки внутри тела цикла для , ничего не путая.

with open("myfile.txt","r") as source:
    rdr= iter(source)
    heading= next(rdr)
    for line in rdr:
        process( line )
2 голосов
/ 21 января 2011

Безопасно, если механизмы находятся под контролем.

============================

.

Нет проблем выполнить итерацию после readline () инструкция

Но есть один для выполнения readline () после итерации

Я создал файл 'rara.txt' с этим текстом (каждая строка имеет длину 5 из-за конца строки \ n в Windows)

1AA
2BB
3CC
4DD
5EE
6FF
7GG
8HH
9II
10j
11k
12l
13m
14n
15o

И я выполнил

FI  = open("rara.txt",'rb')
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
for line in FI:
    cnt += 1
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
    if cnt==4:
        break
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'


lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell()
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

for line in FI:
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

Результат

'1AA\r\n'   len==5  FI.tell() after FI.readline() :  5 

cnt==1   '2BB\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '3CC\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '4DD\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '5EE\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75 


Traceback (most recent call last):
  File "E:\Python\NNN codes\esssssai.py", line 16, in <module>
    lineR = FI.readline()
ValueError: Mixing iteration and read methods would lose data

.

Странная вещь в том, что если мы обновим курсор"by tell () , метод readline () может быть снова активен после итерации (я не знаю, каков закулисный механизм обновления" курсора "):

FI  = open("rara.txt",'rb')
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
for line in FI:
    cnt += 1
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
    if cnt==4:
        pos = FI.tell()
        break
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

FI.seek(pos)

lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell()
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

for line in FI:
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

результат

'1AA\r\n'   len==5  FI.tell() after FI.readline() :  5 

cnt==1   '2BB\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '3CC\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '4DD\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '5EE\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75 

''   len==0  FI.tell() after FI.readline() :  75
''   len==0  FI.tell() after FI.readline() :  75 


FI.tell() after iteration 'for line in FI' :  75 

В любом случае, отметим, что даже если алгоритм должен читать только 4 строки во время итерации (благодаря счетчику cnt ), курсор идет уже в конце файла с самого начала итерацииion: весь файл перед текущей позицией, когда начинается итерация, читается один раз.

Так что pos = FI.tell () до того, как разрыв не даст позицию после4 строки читаются, но позиция конца файла.


.

Мы должны сделать что-то особенное, если мы хотим снова readline () после итерации, из точной точки, в которой заканчивались 4 строки, читающиеся во время итерации:

FI  = open("rara.txt",'rb')
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
pos = FI.tell()
for line in FI:
    cnt += 1
    pos += len(line)
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
    if cnt==4:
        break
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell()
print "    pos   after iteration 'for line in FI' : ",pos,'\n'

FI.seek(pos)

lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell()
lineR = FI.readline()
print repr(lineR)+'   len=='+str(len(lineR))+\
      '  FI.tell() after FI.readline() : ',FI.tell(),'\n'

cnt = 0
for line in FI:
    cnt += 1
    print 'cnt=='+str(cnt)+'   '+repr(line)+'   len=='+str(len(line))+\
          "  FI.tell() after 'line in FI' : ",FI.tell()
print "\nFI.tell() after iteration 'for line in FI' : ",FI.tell(),'\n'

результат

'1AA\r\n'   len==5  FI.tell() after FI.readline() :  5 

cnt==1   '2BB\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '3CC\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '4DD\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '5EE\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75
    pos   after iteration 'for line in FI' :  25 

'6FF\r\n'   len==5  FI.tell() after FI.readline() :  30
'7GG\r\n'   len==5  FI.tell() after FI.readline() :  35 

cnt==1   '8HH\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==2   '9II\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==3   '10j\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==4   '11k\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==5   '12l\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==6   '13m\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==7   '14n\r\n'   len==5  FI.tell() after 'line in FI' :  75
cnt==8   '15o\r\n'   len==5  FI.tell() after 'line in FI' :  75

FI.tell() after iteration 'for line in FI' :  75 

.

Всеэти манипуляции возможны только потому, что файл был открыт в двоичном режиме, потому что я нахожусь в Windows, которая использует '\ r \ n' в качестве конца строк для записи файла, даже если ему приказано писать (в режиме 'w')что-то вроде 'abcdef \ n',

, в то время как с другой стороны Python преобразует (в режиме 'r') все '\ r \ n' в '\ n'.

Этобеспорядок, и чтобы контролировать все это, файлы должны быть открыты в 'rb', если мы хотим делать точные манипуляции.


.

Вы знаете, что ?Я люблю эти игры в позиции файла

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...