Python - разделить файлы

В настоящее время у меня есть скрипт, который запрашивает файл с помощью query.post(). Сервер отправляет мне два файла в одном потоке. То, как я сейчас это делаю, - это сохранить все как один файл, открыть его снова, разделить файл на основе строки регулярного выражения, сохранить как новый файл и удалить старый. Файл достаточно большой, чтобы мне нужно было указать stream=True в моем запросе questions.post() и записать его кусками.

Я надеялся, что, может быть, кто-то знает лучший способ публикации сообщения или работы с возвращающимися данными, чтобы файлы правильно сохранялись с первого раза? Или это лучший способ сделать это?

---- Добавление текущего кода ----

if not os.path.exists(output_path):
    os.makedirs(output_path)

memFile = requests.post(url, data=etree.tostring(etXML), headers=headers, stream=True)

outFile = open('output/tempfile', 'wb')

for chunk in memFile.iter_content(chunk_size=512):
    if chunk:
        outFile.write(chunk)

f = open('output/tempfile', 'rb').read().split('\r\n\r\n')

arf = open('output/recording.arf', 'wb')
arf.write(f[3])
os.remove('output/tempfile')

1 ответ

Решение

Хорошо, мне было скучно, и я хотел найти лучший способ сделать это. Оказывается, мой первоначальный путь в комментариях выше был слишком сложным (если не учитывать какой-то сценарий, когда время абсолютно критично или память сильно ограничена). Буфер является гораздо более простым способом достижения этой цели, если вы берете два или более блоков одновременно. Этот код имитирует сценарий вопросов для демонстрации.

Примечание: в зависимости от реализации движка regex, это более эффективно и требует значительно меньшего количества преобразований str/byte, так как использование regex требует приведения каждого блока байтов к строке. Приведенный ниже подход не требует преобразования строк, а работает только с байтами, возвращенными из request.post()и, в свою очередь, записывает те же байты в файл, без преобразования.

from pprint import pprint

someString = '''I currently have a script that requests a file via a requests.post(). The server sends me two files in the same stream. The way I am processing this right now is to save it all as one file, open it again, split the file based on a regex string, save it as a new file, and delete the old one. The file is large enough that I have to stream=True in my requests.post() statement and write it in chunks.

I was hoping that maybe someone knows a better way to issue the post or work with the data coming back so that the files are stored correctly the first time? Or is this the best way to do it?'''

n = 16
# emulate a stream by creating 37 blocks of 16 bytes
byteBlocks = [bytearray(someString[i:i+n]) for i in range(0, len(someString), n)]
pprint(byteBlocks)

# this string is present twice, but both times it is split across two bytearrays
matchBytes = bytearray('requests.post()')

# our buffer
buff = bytearray()

count = 0
for bb in byteBlocks:
    buff += bb
    count += 1

    # every two blocks
    if (count % 2) == 0:

        if count == 2:
            start = 0
        else:
            start = len(matchBytes)

        # check the bytes starting from block (n -2 -len(matchBytes)) to (len(buff) -len(matchBytes))
        # this will check all the bytes only once...
        if matchBytes in buff[ ((count-2)*n)-start : len(buff)-len(matchBytes) ]:
            print('Match starting at index:', buff.index(matchBytes), 'ending at:', buff.index(matchBytes)+len(matchBytes))

Обновить:

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

Так как вы на самом деле не работаете с потоком напрямую, то есть вы получаете готовый объект ответа из request.post(), вам не нужно беспокоиться об использовании чанков в сетевом смысле. "Куски", на которые ссылаются запросы, на самом деле - это способ выделить байты, из которых у них уже есть все. Вы можете получить доступ к байтам напрямую, используя r.raw.read(n) но, насколько я могу судить, объект запроса не позволяет вам увидеть, сколько байтов содержится в "r.raw", поэтому вы более или менее вынуждены использовать метод "iter_content".

В любом случае, этот код должен скопировать все байты из объекта запроса в строку, затем вы можете искать и разбивать эту строку, как и раньше.

memFile = requests.post(url, data=etree.tostring(etXML), headers=headers, stream=True)

match = '\r\n\r\n'
data = ''

for chunk in memFile.iter_content(chunk_size=512):
    if chunk:
        data += chunk

f = data.split(match)

arf = open('output/recording.arf', 'wb')
arf.write(f[3])
os.remove('output/tempfile')
Другие вопросы по тегам