Как правильно обрабатывать несколько двоичных файлов в python?

В настоящее время я работаю над многопоточным загрузчиком с помощью модуля PycURL. Я загружаю части файлов и потом их объединяю.

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

Это происходит только в Linux env. Тот же скрипт безупречно работает в среде Windows.

Это код (часть скрипта), который объединяет файлы:

with open(filename,'wb') as outfile:
    print('Merging temp files ...')
    for tmpfile in self.tempfile_arr:
        with open(tmpfile, 'rb') as infile:
            shutil.copyfileobj(infile, outfile)
    print('Done!')

Я также пробовал метод write(), но он приводит к той же проблеме, и для больших файлов требуется много памяти.

Если я вручную cat файлы частей в один файл в linux, то контрольная сумма файла совпадает, проблема заключается в слиянии файлов python.

РЕДАКТИРОВАТЬ:
Вот файлы и контрольные суммы (sha256), которые я использовал для воспроизведения проблемы:


person Saumyakanta Sahoo    schedule 28.12.2019    source источник
comment
Я думаю, что ваш режим open не подходит (wb). На основе stackoverflow.com/a/4388244/3727050 вам нужно ab (или r+b и seek)   -  person urban    schedule 28.12.2019
comment
Вам необходимо предоставить минимальный воспроизводимый пример, включая несколько примеров временных файлов. Я думаю, вы сможете воспроизвести проблему с некоторыми временными файлами размером всего в несколько байтов каждый. Надеюсь, размер буфера не является частью проблемы. Также двоичный режим, вероятно, не важен, поэтому вы можете использовать простые текстовые файлы.   -  person wjandrea    schedule 28.12.2019
comment
FWIW К сожалению, мне не удалось воспроизвести проблему с двумя очень короткими текстовыми файлами в Linux.   -  person wjandrea    schedule 28.12.2019
comment
На самом деле pycurl требует двоичного режима для записи данных.   -  person Saumyakanta Sahoo    schedule 28.12.2019
comment
Хорошо, файлы помогают, но ваш код все еще неполный: filename, self.tempfile_arr и shutil не определены   -  person wjandrea    schedule 28.12.2019
comment
Это не весь скрипт, это часть, которая объединяет файлы   -  person Saumyakanta Sahoo    schedule 28.12.2019
comment
Здесь слишком много вещей, которые могут пойти не так, что ваш пример не может исключить: неполные загрузки, tempfile_arr не в том порядке, в котором вы утверждаете, и т. д.   -  person chepner    schedule 13.01.2020
comment
почему вы используете Shutil.copyfileobj`вместо чтения и записи (outfile.write(infile.read()))?   -  person 576i    schedule 13.01.2020
comment
@chepner Я проверяю HTTP-код возврата после загрузки части, как я уже упоминал, точный скрипт работает безупречно в Windows, но повреждает файл в Linux.   -  person Saumyakanta Sahoo    schedule 13.01.2020
comment
@ 576i - функция write() использует много памяти для больших файлов, хотя я пробовал использовать функцию write(), у меня возникла та же проблема.   -  person Saumyakanta Sahoo    schedule 13.01.2020
comment
@ 576i В основном это то, что делает copyfileobj, только он использует буфер фиксированного размера, чтобы избежать одновременного чтения всего исходного файла в память. Это просто цикл повторяющихся x = src.read(SIZE); dst.write(x) вызовов.   -  person chepner    schedule 13.01.2020
comment
Ваши два файла имеют одинаковое содержимое, просто в другом порядке. Другими словами, вы не объединили фрагменты в правильном порядке.   -  person jasonharper    schedule 13.01.2020
comment
@jasonharper да, я тщательно проверил, и действительно, скрипт размещал части в другом порядке. Но почему-то он работал в Windows каждый раз.   -  person Saumyakanta Sahoo    schedule 17.01.2020
comment
Я не могу без ошибок извлечь файл .txt из предоставленного автоматически_merged.tar.gz. Пожалуйста, перезагрузите.   -  person Ente    schedule 05.02.2020
comment
@jasonharper спасибо!! Я решил это, порядок был проблемой   -  person Saumyakanta Sahoo    schedule 07.12.2020
comment
Я использую @urban , я подозреваю, что версия curl для win/linux или ваша библиотека автоматически преобразовывают конец строки или порядок байтов, так что да, выберите какой-нибудь меньший, и что, если файлы не были объединены или затронуты, были ли они одинаковыми контрольная сумма, а в худшем случае вы всегда можете сбросить двоичный файл, чтобы увидеть, что происходит, говорит xxd или hexeditor   -  person Jack Wu    schedule 01.06.2021


Ответы (1)


Минимально воспроизводимый случай был бы удобен, но я подозреваю, что универсальные новые строки быть проблемой: по умолчанию, если ваши файлы представляют собой текст в стиле Windows (новые строки - \r\n), они будут переведены в новые строки в стиле Unix (\n) при чтении. И тогда эти новые строки в стиле unix будут записаны обратно в выходной файл, а не в стиле Windows, как вы ожидали. Это объяснило бы расхождение между python и cat (что вообще не переводило бы).

Попробуйте запустить скрипт, передавая newline='' (пустую строку) в open.

person Masklinn    schedule 13.01.2020