Разделение больших файлов с помощью python

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

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

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.открыть, это f не список, а файловый объект. И, кажется, мы можем только процесс строка за строкой; тогда как я могу выполнить это" сплит " задание? Как я могу указать на определенные строки объекта file?

спасибо

5 ответов


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()

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

если задан необязательный параметр 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 

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()

для файла 10GB второй подход-это явно путь. Вот набросок того, что вам нужно сделать:

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

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

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

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