Сплит большие файлы с помощью Python - PullRequest
9 голосов
/ 11 ноября 2011

У меня возникли проблемы при попытке разбить большие файлы (скажем, около 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.open это f не список, а объект файла. И, кажется, мы можем обрабатывать только построчно; тогда как я могу выполнить эту «разделенную» работу? Как я могу указать на определенные строки файлового объекта?

Спасибо

Ответы [ 5 ]

15 голосов
/ 11 ноября 2011
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()
4 голосов
/ 11 ноября 2011

Если нет ничего особенного в том, чтобы иметь определенное количество строк в каждом файле, функция 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 
3 голосов
/ 11 ноября 2011
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()
2 голосов
/ 11 ноября 2011

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

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

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

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

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

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