Печатать определенные строки из нескольких файлов в Python
У меня есть 30 текстовых файлов по 30 строк в каждом. По какой-то причине мне нужно написать скрипт, который открывает файл 1, печатает строку 1 файла 1, закрывает его, открывает файл 2, печатает строку 2 файла 2, закрывает его и так далее. Я попробовал это:
import glob
files = glob.glob('/Users/path/to/*/files.txt')
for file in files:
i = 0
while i < 30:
with open(file,'r') as f:
for index, line in enumerate(f):
if index == i:
print(line)
i += 1
f.close()
continue
Очевидно, я получил следующую ошибку:
ValueError: операция ввода-вывода для закрытого файла.
Из-за f.close(). Как я могу сделать, чтобы перейти от файла к следующему после чтения только нужной строки?
4 ответа
Прежде всего, чтобы ответить на вопрос, как отмечено в комментариях, ваша основная проблема заключается в том, что вы закрываете файл, а затем пытаетесь продолжить его повторение. Виновный код:
for index, line in enumerate(f): # <-- Reads
if index == i:
print(line)
i += 1
f.close() # <-- Closes when you get a hit
# But loop is not terminated, so you'll loop again
Самое простое решение - просто break
вместо того, чтобы явно закрывать, так как ваш with
оператор уже гарантирует детерминированное закрытие при выходе из блока:
for index, line in enumerate(f):
if index == i:
print(line)
i += 1
break
Но так как это было забавно, вот немного очищенного кода для выполнения той же задачи:
import glob
from itertools import islice
# May as well use iglob since we'll stop processing at 30 files anyway
files = glob.iglob('/Users/path/to/*/files.txt')
# Stop after no more than 30 files, use enumerate to track file num
for i, file in enumerate(islice(files, 30)):
with open(file,'r') as f:
# Skip the first i lines of the file, then print the next line
print(next(islice(f, i, None)))
Вы можете использовать linecache
Модуль, чтобы получить нужную вам линию и избавить себя от головной боли:
import glob
import linecache
line = 1
for file in glob.glob('/Users/path/to/*/files.txt'):
print(linecache.getline(file, line))
line += 1
if line > 30: # if you really need to limit it to only 30
break
Разделите свою работу на более простые шаги, пока последний шаг не станет тривиальным. Используйте функции.
Помните, что файловый объект работает как последовательность строк.
def nth(n, sequence):
for position, item in enumerate(sequence):
if position == n:
return item
return None # if the sequence ended before position n
def printNthLines(glob_pattern)
# Note: sort file names; glob guarantees no order.
filenames = sorted(glob.glob(glob_pattern))
for position, filename in enumerate(filenames):
with open(filename) as f:
line = nth(position, f) # Pick the n-th line.
if line is not None:
print(line)
# IDK what to do if there's no n-th line in n-th file
printNthLines('path/to/*/file.txt')
Очевидно, что мы сканируем n-й файл в n-ю строку, но это неизбежно, нет способа напрямую перейти к n-й строке в текстовом файле.
Я думаю, что-то вроде этого, что вы хотите:
import glob
files = glob.glob('/Users/path/to/*/files.txt')
for file in files:
i = 0
while i < 30:
with open(file,'r') as f:
for index, line in enumerate(f):
if index == i:
print(line)
i += 1
break
f.close()
В настоящее время вы закрываете файл в середине цикла for, а затем снова пытаетесь его прочитать. Так что если вы закрываете файл только после выхода из цикла for, все будет в порядке.