2011-11-11 16 views
7

У меня есть некоторые проблемы с попыткой разделить большие файлы (скажем, около 10 ГБ). Основная идея - просто читать строки и группировать каждый, скажем 40000 строк в один файл. Но есть два способа «чтения» файлов.Сплит больших файлов с использованием python

1) Первый из них заключается в том, чтобы сразу прочитать файл WHOLE и внести его в список. Но для этого потребуется загрузить файл WHOLE в память, что является болезненным для слишком большого файла. (Я думаю, что я задавал такие вопросы раньше) В питоне, подходы читать весь файл, как только я попытался включить:

input1=f.readlines() 

input1 = commands.getoutput('zcat ' + file).splitlines(True) 

input1 = subprocess.Popen(["cat",file], 
           stdout=subprocess.PIPE,bufsize=1) 

Ну, тогда я могу только легко группировать 40000 строк в один файл по: list[40000,80000] or list[80000,120000] Или преимущество использования списка состоит в том, что мы можем легко указать на определенные строки.

2) Второй способ - читать по строкам; обрабатывать линию при ее чтении. Эти строки чтения не будут сохранены в памяти. Примеры включают:

f=gzip.open(file) 
for line in f: blablabla... 

или

for line in fileinput.FileInput(fileName): 

Я уверен, что для gzip.open, это е НЕ список, а объектный файл. И кажется, что мы можем обрабатывать только строки за строкой; то как я могу выполнить эту «расколотую» работу? Как я могу указать на конкретные строки файлового объекта?

Благодаря

+0

Когда вы думаете об этом, вы не можете. Вы можете знать только, на какой строке вы находитесь, только после того, как вы прочитали все предыдущие строки и подсчитали разрывы строк (\ n). (Игнорирование особого случая, что это какой-то странный файл, в котором каждая строка имеет известную длину.) – rplnt

ответ

11
NUM_OF_LINES=40000 
filename = 'myinput.txt' 
with open(filename) as fin: 
    fout = open("output0.txt","wb") 
    for i,line in enumerate(fin): 
     fout.write(line) 
     if (i+1)%NUM_OF_LINES == 0: 
     fout.close() 
     fout = open("output%d.txt"%(i/NUM_OF_LINES+1),"wb") 

    fout.close() 
+0

Если вы хотите ровно 40 000 строк в файл, я думаю, вы должны инициализировать 'i'' 0', а не '1'. – martineau

+2

Зачем использовать fileinput ?? –

+0

Какие пакеты вам нужны? –

2

Для файла 10GB, второй подход, безусловно, путь. Ниже приведен обзор того, что вам нужно сделать:

  1. Открыть входной файл.
  2. Откройте первый выходной файл.
  3. Прочитайте одну строку из входного файла и запишите ее в выходной файл.
  4. Поддержание количества строк, которые вы написали в текущий выходной файл; как только он достигнет 40000, закройте выходной файл и откройте следующий.
  5. Повторите шаги 3-4 до тех пор, пока вы не достигнете конца входного файла.
  6. Закрыть оба файла.
+0

'if num_lines% 4000 == 0: avoid_writing_empty_file_at_end() #, за исключением случаев, когда numlines == 0' –

3
chunk_size = 40000 
fout = None 
for (i, line) in enumerate(fileinput.FileInput(filename)): 
    if i % chunk_size == 0: 
     if fout: fout.close() 
     fout = open('output%d.txt' % (i/chunk_size), 'w') 
    fout.write(line) 
fout.close() 
+0

Вам нужно сделать 'if fout: fout.close()' после выхода из цикла –

+0

Спасибо, @JohnMachin. Исправлена. –

4

Если нет ничего особенного, имеющие определенное количество файлов строк в каждом файле, то readlines() function также принимает параметр размера «подсказку», которая ведет себя так:

If с учетом необязательного параметра sizehint, он читает, что много байтов от файла и еще достаточно для завершения строки и возвращает строки . Это часто используется для эффективного чтения большого файла по строкам, но без необходимости загрузки всего файла в память. Возвращаются только полные строки.

...так что вы могли бы написать, что код что-то вроде этого:

# assume that an average line is about 80 chars long, and that we want about 
# 40K in each file. 

SIZE_HINT = 80 * 40000 

fileNumber = 0 
with open("inputFile.txt", "rt") as f: 
    while True: 
     buf = f.readlines(SIZE_HINT) 
     if not buf: 
     # we've read the entire file in, so we're done. 
     break 
     outFile = open("outFile%d.txt" % fileNumber, "wt") 
     outFile.write(buf) 
     outFile.close() 
     fileNumber += 1 
+0

-1 (1) вы явно не закрываете выходные файлы (2), читаете в текстовом режиме, а запись в двоичном режиме ГАРАНТИРОВАНА для «mung things, если мы на окнах» –

+0

(3) отступ 'fileNumber + = 1' неверно –

+0

@JohnMachin правильный X 3. Спасибо, что поймал мою неряшливость. – bgporter

0

Очевидно, что вы делаете работу на файл, вам нужно будет перебирать содержимое файла в некотором роде - делать ли это вручную или позволить часть API Python делает это для вас (например, метод readlines()) не имеет значения. В большом анализе O это означает, что вы потратите время O (n) (n - размер файла).

Но для чтения файла в память также требуется O (n) пространство. Хотя иногда нам нужно прочитать 10-гигабайтный файл в памяти, ваша конкретная проблема не требует этого. Мы можем напрямую перебирать файл. Конечно, файловый объект требует пространства, но у нас нет причин держать содержимое файла дважды в двух разных формах.

Поэтому я бы пошел со своим вторым решением.

Смежные вопросы