Хэшировать файл блоками по 64 МБ?

Хэшировать файл блоками по 64 МБ?

У меня очень большой файл (200 ГБ). Видимо, когда я его перенес, он не скопировался правильно. Хэш sha1 на обоих файлах разный. Есть ли способ разделить файл на блоки (например, 1 МБ или 64 МБ) и вывести хэш для каждого блока? Затем сравнить/исправить?

Я мог бы просто написать быстрое приложение, которое сделает это.

решение1

Это "быстрое приложение" уже существует и довольно распространено: rsync. Конечно, rsync может делать гораздо больше, но то, что вам нужно, довольно просто:

rsync -cvP --inplace user@source:src-path-to-file dest-path-to-file   # from the destination
rsync -cvP --inplace src-path-to-file user@dest:dest-path-to-file     # from the source

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

Я сдал следующие варианты:

  • -c— пропуск на основе контрольных сумм, а не размера файла/mtime. По умолчанию rsync оптимизирует и пропускает передачи, где размер и mtime совпадают. -cзаставляет его вычислять контрольную сумму (что является дорогостоящей операцией с точки зрения ввода-вывода). Обратите внимание, что это контрольная сумма на основе блоков (если только вы не укажете ему делать только целые файлы), и он передаст только поврежденные блоки. Размер блока выбирается автоматически, но его можно переопределить -B(сомневаюсь, что для этого есть какие-либо причины).
  • -v— подробный, предоставит некоторые подробности (над каким файлом он работает)
  • -P— включает как частичные файлы (чтобы при достижении середины работа не была потеряна), так и индикатор выполнения.
  • --inplace— Обновите существующий файл, а не временный файл (который затем заменит исходный файл). Избавляет вас от временного файла размером 200 ГБ. Также подразумевает частичные файлы, так что это -Pчастично избыточно.

BTW: Я не уверен, как вы сделали изначальный перенос, но если это был sftp/scp, то что-то очень не так — они полностью защищают от любого повреждения в сети. Вам действительно следует отследить причину. Неисправная RAM — довольно распространенная проблема.

решение2

Если вы хотите повторно передать файл на другой компьютер через сетевое соединение,использовать rsync.

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

Этот метод основан на head -cсохранении позиции файла в том месте, где он был остановлен, и предварительном вычислении размера, чтобы знать, где закончить цикл.

n=$(($(wc -c <very_large_file) / (64*1024*1024) + 1))
i=0
while [ $i -gt $n ]; do
    head -c 64m | sha256sum
    i=$((i+1))
done <very_large_file

Этот метод основан на head -cсохранении позиции файла там, где он был остановлен, и использует cksumдля определения размера каждого фрагмента (короткий фрагмент указывает на конец файла).

while true; do
    output=$(head -c 64m | cksum)
    size=${output#* }; size=${output%% *}
    if [ $size -eq 0 ]; then break; fi
    echo "$output"
done <very_large_file

Этот метод вызывает ddпереход к желаемой начальной позиции для каждого фрагмента.

n=$(($(wc -c <very_large_file) / (64*1024*1024) + 1))
i=0
while [ $i -gt $n ]; do
    dd if=very_large_file ibs=64m skip=$i count=1 | sha256sum
    i=$((i+1))
done <very_large_file

решение3

Вам, вероятно, следует обратить внимание на split:

Вот страница руководства с примерами:

https://ss64.com/bash/split.html

Связанный контент