Изменить файл Python на месте - PullRequest
8 голосов
/ 17 июля 2009

У меня есть большой XML-файл (40 Гб), который мне нужно разбить на более мелкие куски. Я работаю с ограниченным пространством, есть ли способ удалить строки из исходного файла, когда я записываю их в новые файлы?

Спасибо!

Ответы [ 7 ]

7 голосов
/ 18 июля 2009

Скажем, вы хотите разбить файл на N частей, а затем просто начать чтение с конца файла (более или менее) и многократно вызывать усечение :

Сокращение размера файла. Если указан необязательный аргумент размера, файл усекается до (максимально) этого размера. Размер по умолчанию соответствует текущей позиции. Текущая позиция файла не изменяется. ...

import os
import stat

BUF_SIZE = 4096
size = os.stat("large_file")[stat.ST_SIZE]
chunk_size = size // N 
# or simply set a fixed chunk size based on your free disk space
c = 0

in_ = open("large_file", "r+")

while size > 0:
    in_.seek(-min(size, chunk_size), 2)
    # now you have to find a safe place to split the file at somehow
    # just read forward until you found one
    ...
    old_pos = in_.tell()
    with open("small_chunk%2d" % (c, ), "w") as out:
        b = in_.read(BUF_SIZE)
        while len(b) > 0:
            out.write(b)
            b = in_.read(BUF_SIZE)
    in_.truncate(old_pos)
    size = old_pos
    c += 1

Будь осторожен, я не проверял ничего из этого. Может потребоваться вызвать flush после вызова усечения, и я не знаю, насколько быстро файловая система собирается освободить пространство.

2 голосов
/ 17 июля 2009

Если вы работаете в Linux / Unix, почему бы не использовать команду split, как этот парень делает?

split --bytes=100m /input/file /output/dir/prefix

РЕДАКТИРОВАТЬ: затем используйте csplit .

1 голос
/ 17 июля 2009

Я почти уверен, что есть, так как я даже смог редактировать / читать из исходных файлов скриптов, которые я запускал, но самой большой проблемой, вероятно, было бы все смещение, которое было бы сделано, если бы вы начали в начале файла. С другой стороны, если вы просматриваете файл и записываете все начальные позиции строк, вы можете затем перейти в обратном порядке, чтобы скопировать строки; как только это будет сделано, вы можете вернуться, взять новые файлы, по одному, и (если они достаточно малы), использовать readlines (), чтобы сгенерировать список, изменить порядок списка, затем перейти к началу файла и перезаписать строки в старом порядке строками в новом.

(Вы должны обрезать файл после прочтения первого блока строк с конца, используя метод truncate(), который обрезает все данные после текущей позиции файла, если используется без каких-либо аргументов, кроме аргумента объекта файла, предполагая, что вы Вы используете один из классов или подкласс одного из классов из пакета io для чтения вашего файла. Вам просто нужно убедиться, что текущая позиция файла заканчивается в начале последней строки, которая будет записано в новый файл.)

РЕДАКТИРОВАТЬ: Исходя из вашего комментария о необходимости разделения в правильных закрывающих тегах, вам, вероятно, также придется разработать алгоритм для обнаружения таких тегов (возможно, с использованием метода peek), возможно, с использованием регулярного выражения .

0 голосов
/ 20 июля 2009

Вот мой сценарий ...

import string
import os
from ftplib import FTP

# make ftp connection
ftp = FTP('server')
ftp.login('user', 'pwd')
ftp.cwd('/dir')

f1 = open('large_file.xml', 'r')

size = 0
split = False
count = 0

for line in f1:
  if not split:
    file = 'split_'+str(count)+'.xml'
    f2 = open(file, 'w')
    if count > 0:
      f2.write('<?xml version="1.0"?>\n')
      f2.write('<StartTag xmlns="http://www.blah/1.2.0">\n')
    size = 0
    count += 1 
    split = True    
  if size < 1073741824:
      f2.write(line)
      size += len(line)
  elif str(line) == '</EndTag>\n':
      f2.write(line)
      f2.write('</EndEndTag>\n')
      print('completed file %s' %str(count))
      f2.close()
      f2 = open(file, 'r')
      print("ftp'ing file...")
      ftp.storbinary('STOR ' + file, f2)
      print('ftp done.')
      split = False
      f2.close()
      os.remove(file)
  else:
    f2.write(line)
    size += len(line)
0 голосов
/ 19 июля 2009

Самое время купить новый жесткий диск!

Вы можете сделать резервную копию, прежде чем пытаться ответить на все остальные вопросы, и не потерять данные :)

0 голосов
/ 18 июля 2009

Вы всегда можете проанализировать файл XML и записать, скажем, каждые 10000 элементов в свой собственный файл. Посмотрите на раздел «Инкрементальный анализ» этой ссылки. http://effbot.org/zone/element-iterparse.htm

0 голосов
/ 17 июля 2009

Если время не является основным фактором (или износ вашего дисковода):

  1. Открыть дескриптор файла
  2. Считайте до размера вашего раздела / логической точки останова (из-за xml)
  3. Сохраните оставшуюся часть вашего файла на диск (не уверен, как python справится с этим, вплоть до прямой перезаписи файла или использования памяти)
  4. Запись раздела на диск
  5. Перейти к 1

Если Python не дает вам такого уровня контроля, вам, возможно, придется погрузиться в C.

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