Все в порядке, пока вы не дойдете до точки, где вы попытаетесь склеить все прочитанные фрагменты вместе и записать результат в повторно собранный файл "rebuilt_sample.png". Все шаги до этого момента (чтение исходного файла, разбиение его на куски, запись фрагментов в отдельные файлы, чтение файлов фрагментов обратно) обрабатывают данные файла как буферы, содержащие байты, которые не были проверены или интерпретированы в любым способом.
Но тогда это происходит:
fs.createWriteStream("rebuilt_" + fileName).write(Buffer.concat(resFromChunk).toString());
В этом операторе вызов toString()
приводит к тому, что байты в объединенном буфере интерпретируются (или «декодируются») как символы, а затем во время операции write()
эти символы преобразуются (или «кодируются») обратно. в байтовый поток, который записывается в файл. Действия по декодированию и кодированию выполняются в соответствии с правилами локали вашей программы, которая, вероятно, является локалью UTF-8. UTF-8 - это метод для перевода символов Юникода в последовательность байтов и из нее.
Отлично IF Все байты в буфере могут быть успешно декодированы как символы по правилам UTF-8. Это очень вероятно, когда входной файл представляет собой текстовый файл, например .txt
или .js
. Но когда файл представляет собой нетекстовый файл (часто называемый «двоичным» файлом), вполне вероятно, что некоторые последовательности байтов в файле не будут допустимыми последовательностями байтов UTF-8, и поэтому эти байты не будут переводиться в символы , Это произойдет почти для всех байтов, значение которых больше 127 десятичных, 0x7F шестнадцатеричных. Ваш sample.png
является одним из этих двоичных файлов, который содержит некоторые байты, которые не могут быть переведены в символы.
Есть несколько способов, которыми программа может реагировать на непереводимые байты. Например, может произойти сбой, он может молча пропустить эти байты, он может пропустить их и выдать отчет об ошибке, он может прекратить перевод после просмотра неверного байта, он может создать полностью пустую строку. В этом случае узел тихо преобразует каждый недопустимый байт в символ замены Unicode « » в сгенерированной строке. Затем, когда эта строка кодируется обратно в байты во время операции write()
, каждый из этих символов замещения преобразуется в соответствии с правилами UTF-8 и становится трехбайтовой последовательностью 0xEF 0xBF 0xFD
в восстановленном файле.
Вот почему ваш восстановленный файл больше оригинального. Почти каждый байт в исходном файле, значение которого было больше 0x7F, заменяется на три байта в перестроенном файле.
Исправить эту проблему легко. Просто избавьтесь от вызова .toString()
в этой строке и позвольте вашей программе обрабатывать объединенный буфер как не интерпретируемый набор байтов:
fs.createWriteStream("rebuilt_" + fileName).write(Buffer.concat(resFromChunk))