Разделение большого текстового файла на более мелкие текстовые файлы по номерам строк с использованием Python
У меня есть текстовый файл say really_big_file.txt, который содержит:
line 1
line 2
line 3
line 4
...
line 99999
line 100000
Я хотел бы написать Python script, который делит файл real_big_file.txt на более мелкие файлы по 300 строк. Например, small_file_300.txt имеет строки 1-300, small_file_600 для строк 301-600 и т.д., Пока не будет достаточно маленьких файлов, сделанных для того, чтобы содержать все строки из большого файла.
Я был бы признателен за любые предложения по простейшему способу выполнения этого с помощью Python
Ответы
Ответ 1
Использование itertools
grouper рецепт:
from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
n = 300
with open('really_big_file.txt') as f:
for i, g in enumerate(grouper(n, f, fillvalue=''), 1):
with open('small_file_{0}'.format(i * n), 'w') as fout:
fout.writelines(g)
Преимущество этого метода в отличие от хранения каждой строки в списке состоит в том, что он работает с итерами, по очереди, поэтому ему не нужно хранить каждый small_file
в памяти сразу.
Обратите внимание, что последний файл в этом случае будет small_file_100200
, но будет работать только до line 100000
. Это происходит потому, что fillvalue=''
, что означает, что я ничего не записываю в файл, когда у меня больше нет строк для записи, потому что размер группы не делится одинаково. Вы можете исправить это, написав временный файл, а затем переименовав его, вместо того, чтобы называть его первым, как я. Вот как это можно сделать.
import os, tempfile
with open('really_big_file.txt') as f:
for i, g in enumerate(grouper(n, f, fillvalue=None)):
with tempfile.NamedTemporaryFile('w', delete=False) as fout:
for j, line in enumerate(g, 1): # count number of lines in group
if line is None:
j -= 1 # don't count this line
break
fout.write(line)
os.rename(fout.name, 'small_file_{0}.txt'.format(i * n + j))
В этот раз fillvalue=None
и я просматриваю каждую строку, проверяя None
, когда это происходит, я знаю, что процесс завершился, поэтому я вычитаю 1
из j
, чтобы не считать наполнитель, а затем написать файл.
Ответ 2
lines_per_file = 300
smallfile = None
with open('really_big_file.txt') as bigfile:
for lineno, line in enumerate(bigfile):
if lineno % lines_per_file == 0:
if smallfile:
smallfile.close()
small_filename = 'small_file_{}.txt'.format(lineno + lines_per_file)
smallfile = open(small_filename, "w")
smallfile.write(line)
if smallfile:
smallfile.close()
Ответ 3
import csv
import os
import re
MAX_CHUNKS = 300
def writeRow(idr, row):
with open("file_%d.csv" % idr, 'ab') as file:
writer = csv.writer(file, delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
writer.writerow(row)
def cleanup():
for f in os.listdir("."):
if re.search("file_.*", f):
os.remove(os.path.join(".", f))
def main():
cleanup()
with open("large_file.csv", 'rb') as results:
r = csv.reader(results, delimiter=',', quotechar='\"')
idr = 1
for i, x in enumerate(r):
temp = i + 1
if not (temp % (MAX_CHUNKS + 1)):
idr += 1
writeRow(idr, x)
if __name__ == "__main__": main()
Ответ 4
Я делаю это более понятным способом и использую менее короткие сокращения, чтобы дать вам дополнительное представление о том, как и почему это работает. Предыдущие ответы работают, но если вы не знакомы с определенными встроенными функциями, вы не поймете, что делает функция.
Поскольку вы не размещали код, я решил сделать это так, потому что вы могли быть незнакомы с вещами, отличными от базового синтаксиса python, учитывая, что, как вы сформулировали этот вопрос, казалось, что вы не пытались и не знали, как подойти к вопросу
Ниже приведены шаги для этого в базовом python:
Сначала вы должны прочитать свой файл в списке для хранения:
my_file = 'really_big_file.txt'
hold_lines = []
with open(my_file,'r') as text_file:
for row in text_file:
hold_lines.append(row)
Во-вторых, вам нужно создать способ создания новых файлов по имени! Я бы предложил цикл с парами счетчиков:
outer_count = 1
line_count = 0
sorting = True
while sorting:
count = 0
increment = (outer_count-1) * 300
left = len(hold_lines) - increment
file_name = "small_file_" + str(outer_count * 300) + ".txt"
В-третьих, внутри этого цикла вам понадобятся несколько вложенных циклов, которые сохранят правильные строки в массиве:
hold_new_lines = []
if left < 300:
while count < left:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
sorting = False
else:
while count < 300:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
Наконец, снова в первом цикле вам нужно написать новый файл и добавить свой последний счетчик, чтобы ваш цикл снова прошел и написал новый файл
outer_count += 1
with open(file_name,'w') as next_file:
for row in hold_new_lines:
next_file.write(row)
обратите внимание: если количество строк не делится на 300, последний файл будет иметь имя, которое не соответствует последней строке файла.
Важно понять, почему эти петли работают. Вы настроили его так, чтобы в следующем цикле имя файла, который вы записываете, изменяется, потому что у вас есть имя, зависящее от изменяющейся переменной. Это очень полезный скриптовый инструмент для доступа к файлам, открытия, записи, организации и т.д.
Если вы не могли следовать тому, что было в этом цикле, вот полнота функции:
my_file = 'really_big_file.txt'
sorting = True
hold_lines = []
with open(my_file,'r') as text_file:
for row in text_file:
hold_lines.append(row)
outer_count = 1
line_count = 0
while sorting:
count = 0
increment = (outer_count-1) * 300
left = len(hold_lines) - increment
file_name = "small_file_" + str(outer_count * 300) + ".txt"
hold_new_lines = []
if left < 300:
while count < left:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
sorting = False
else:
while count < 300:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
outer_count += 1
with open(file_name,'w') as next_file:
for row in hold_new_lines:
next_file.write(row)
Ответ 5
lines_per_file = 300 # Lines on each small file
lines = [] # Stores lines not yet written on a small file
lines_counter = 0 # Same as len(lines)
created_files = 0 # Counting how many small files have been created
with open('really_big_file.txt') as big_file:
for line in big_file: # Go throught the whole big file
lines.append(line)
lines_counter += 1
if lines_counter == lines_per_file:
idx = lines_per_file * (created_files + 1)
with open('small_file_%s.txt' % idx, 'w') as small_file:
# Write all lines on small file
small_file.write('\n'.join(stored_lines))
lines = [] # Reset variables
lines_counter = 0
created_files += 1 # One more small file has been created
# After for-loop has finished
if lines_counter: # There are still some lines not written on a file?
idx = lines_per_file * (created_files + 1)
with open('small_file_%s.txt' % idx, 'w') as small_file:
# Write them on a last small file
small_file.write('n'.join(stored_lines))
created_files += 1
print '%s small files (with %s lines each) were created.' % (created_files,
lines_per_file)