두 개의 유사한 큰 원시 바이너리 파일의 차이

내에 4GB 파일 abc이 있다고 가정 해 보겠습니다. 로컬 컴퓨터입니다. SFTP를 통해 원격 서버에 업로드했는데 몇 시간이 걸렸습니다.

이제 파일을 약간 수정했습니다 (최대 50MB이지만이 파일의 연속 바이트는 아님). abc2에 저장했습니다. 또한 로컬 컴퓨터에 원본 파일 abc도 보관했습니다.

abcabc2의 이진 차이를 계산하는 방법은 무엇입니까?

애플리케이션 :

  • patch 파일 (최대 100MB) 만 보낼 수 있습니다. 전체 abc2 파일을 다시 업로드하는 대신 (몇 시간이 다시 소요됩니다!) 원격 서버에서 abc2를 다시 만듭니다. abcpatch의 서버에만 해당됩니다.

  • abcabc2 백업에 8GB를 낭비하는 대신 로컬에서 abc + patch, 따라서 < 4100MB 만 필요합니다.

어떻게해야합니까?

PS : 텍스트의 경우 diff를 알고 있지만 여기서는 모든 원시 바이너리 형식에 대해 작동 할 수있는 것, zip 파일, 실행 파일 또는 다른 유형의 파일 일 수 있습니다.

PS2 : 가능하면 ; 두 컴퓨터간에 변경 사항을 효율적으로 복제 할 수 있다는 것을 알고 있지만 (변경되지 않은 데이터를 재전송하지 않음) 여기서는 나중에 재현 할 수있는 patch 파일을 원합니다. abcpatch가 모두 있습니다.

답변

두 번째 응용 프로그램 / 문제의 경우 시도하는 대신 restic 또는 borgbackup와 같은 중복 제거 백업 프로그램을 사용합니다. “패치”또는 차이점을 수동으로 추적합니다. restic 백업 프로그램을 사용하면 여러 머신의 디렉토리를 동일한 백업 저장소로 백업하여 개별 머신의 파일 조각과 머신간에 백업 데이터를 중복 제거 할 수 있습니다. (borgbackup에 대한 사용자 경험이 없으므로 해당 프로그램에 대해 아무 말도 할 수 없습니다.)

abcabc2 파일은 rsync로 수행 할 수 있습니다.

예 : abcabc2는 153MB입니다. abc2 파일은 다른 데이터와 함께 파일의 처음 2.3MB :

 $ ls -lh total 626208 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2  

abcabc2로 변환하고 이름을 abc-diff로 지정하기위한 패치 :

 $ rsync --only-write-batch=abc-diff abc2 abc  
 $ ls -lh total 631026 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw------- 1 kk wheel 2.3M Feb 3 17:03 abc-diff -rwx------ 1 kk wheel 38B Feb 3 17:03 abc-diff.sh -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2  

생성 된 파일 abc-diff는 실제 diff ( “패치 파일”)이고 abc-diff.shrsync가 생성하는 짧은 셸 스크립트 :

 $ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}  

이 스크립트는 iv id = “f91b090ab2 파일이 주어지면 abcabc2와 동일하게 수정합니다. “>

:

 $ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2  

파일 abc-diff는 이제 abc가있는 다른 곳으로 이전 될 수 있습니다. rsync --read-batch=abc-diff abc 명령을 사용하여 패치를 abc 파일에 적용하여 해당 내용을 abc2 파일입니다.

패치를 다시 적용하는 것이 안전 해 보입니다. 오류 메시지도없고 파일 내용도 변경되지 않습니다 (MD5 체크섬은 변경되지 않음).

명시적인 “역 패치”를 생성하지 않는 한 응용 프로그램을 쉽게 실행 취소 할 수있는 방법이 없습니다.


또한 2.3MB 수정을 abc2 데이터의 다른 위치에 기록하는 것을 테스트했습니다. 생성 된 “패치”의 크기는 4.6MB로 수정 된 비트 만 패치에 저장되었음을 나타냅니다.

댓글

  • @Kusalananda에게 감사합니다. ‘ 좋습니다. PS : rsync --read-batch=abc-diff ${1:-abc} (자동으로 생성 된 .sh 스크립트)가 remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2] 그러나 rsync --read-batch=abc-diff abc는 성공적으로 작동했습니다.이 두 가지 유사한 명령의 차이점은 무엇입니까?
  • 2/2 abc를 입력으로 받아들이고 패치를 적용하는 방법이 있습니까? diff-abc --read-batch를 사용하지만 abc ” 현재 위치 ” 대신 새 파일 abc3로 출력 하시겠습니까? (가능한 경우 파이프없이 rsync를 사용하여 모두 Linux 및 rsync.exe를 사용할 수있는 Windows에서도 쉽게 작동하도록합니다.)
  • @Basj $1에 값이 있으면 명령이 다른 작업을 수행합니다. ${1:-abc}는 ” 첫 번째 위치 매개 변수 ($1)를 사용함을 의미합니다. ‘이 비어 있거나 정의되지 않았습니다. 비어 있거나 정의되지 않은 경우 ‘ 대신 abc를 ” 사용하세요. 저는 ‘ $1 시도했을 때 값이 있다 라고 가정합니다. 원격 대상 주소입니다.
  • @Basj I ‘이 작업이 가능하다는 것은 확실하지 않지만 ‘ 내일 수면 후에 살펴보세요.
  • ${1:-abc}에 대한 답변을 주셔서 감사합니다. Windows에서 시도했기 때문에 실패했을 수 있습니다 (‘ 원격 서버용 Linux와 Windows 로컬에서 모두 rsync를 사용하고 있습니다). 하지만 ‘ rsync --read-batch=abc-diff abc가 작동하므로 완벽합니다. 🙂

답변

abc와 abc2의 이진 차이를 계산하는 방법

bsdiff / bspatch 또는 xdelta 및 기타 사용

$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created 

그러나 man 페이지의 다음 권고 사항에 유의해야합니다.

  • bsdiff는 크기의 17 배에 해당하는 메모리를 사용합니다. oldfile , oldfile 크기의 8 배인 절대 최소 작업 세트 크기가 필요합니다.
  • bspatch oldfile 크기에 newfile 크기를 더한 것과 동일한 메모리를 사용하지만 성능 저하없이 매우 작은 작업 집합을 허용 할 수 있습니다.

댓글

  • 예를 보여 주시겠습니까?
  • 답변 해 주셔서 감사합니다. bsdiff uses memory equal to 17 times the size of oldfile 따라서이 방식은 ‘ 일반적으로 4GB 파일 (최소한 내 8GB RAM 시스템)에서는 작동하지 않습니다.
  • @Basj 가능한 것은 4GB 파일을 더 작은 파일 (예 : 각각 128MB)로 자르고 개별 델타를 수행하는 것입니다. 이것은 스크립트로 래핑 될 수 있습니다. chopped-bsdiff : 파일을 자르고, bsdiff를 쌍으로 수행하고, 파일을 아카이브로 tar합니다. chopped-bspatch : 아카이브에서 쌍별 패치를 읽고, 입력 파일 청크에 적용하고, 출력을 분류합니다.
  • @Kaz 알지만 ‘ 더 많이 찾고 있습니다. 크기에 관계없이 한 줄 (mydiff abc abc2 > patchfilemypatch abc patchfile > abc3)로 호출 할 수있는 바로 사용할 수있는 도구입니다. 또한 128MB 청크로 자르면 abc의 처음 1GB == abc2의 마지막 (후행) 1GB이면 어떻게됩니까? ? ‘ abc-first128mbabc2-first128mb와 비교할 때 일치하는 항목이 없으므로 효율적이지 않을 수 있습니까?

답변

강제 diff : 파일을 텍스트로 처리 :

diff -ua abc abc2 

여기 에 설명 된대로.

  • -u 통합 컨텍스트의 NUM (기본값 3) 줄 출력
  • -a 모든 파일을 텍스트로 처리

이렇게하면 패치를받을 수 있습니다. 단점은 “줄”이 상당히 길 수 있고 패치를 부 풀릴 수 있다는 것입니다.

댓글

  • 이런, 그렇습니다. ‘ 실제로 n를 원하지 않습니다. ‘이 작동하는지 알고 싶습니다. ‘ ” 라인 “이됩니다.
  • 댓글 감사합니다! 두 개의 매우 유사한 256MB 파일 abcabc2를 만들었습니다. 그런 다음 diff -ua abc abc2 > patch를 시도한 다음 abcabc3에 복사하고 복구를 시도했습니다. abc3 및 patch 덕분에 div id = “969241e5c0”>

:patch abc3 < patch그러나 작동하지 않았습니다. 마지막에abc3는 256MB 대신 1KB였습니다. 아시나요?

  • 음, 무슨 일이 있었는지 모르겠네요. 내 컴퓨터에서 방금했고 예상했던 것보다 더 잘 작동했습니다.바이너리로 작성된 임의의 정수인 382M 파일을 파일로 가져 왔습니다. 나는 그것에 3 바이트를 변경하고 diff 및 패치를 수행했으며 작동했습니다. 결과 파일은 md5sum이 같았습니다.
  • 큰 파일에 바이트가 0x0a, 즉 개행이 없거나 매우 적 으면 ‘ 잘 작동하지 않습니다. 테스트 해 보면 흥미로울 것입니다.
  • 그렇습니다. 줄 바꿈을 찾고 내 경험상 매우 빠르게 실행되는 wc -l를 사용하여 바이너리에 대해 교육적인 추측을 할 수 있습니다. 임의의 바이너리에서 꽤 잘 작동 할 것으로 예상합니다. 예를 들어 내 컴퓨터에서 120 만 개의 ” 라인 “과 59M 는 약 230k이므로 평균 ” 라인 “은 각각 220 바이트 및 258 바이트 미만입니다. ‘이 파일이 다른 파일과 다른 이유는 알 수 없지만 분명히 운이 좋지 않을 수 있습니다. 실제로 나는 그것이 꽤 잘 작동 할 것이라고 생각하며 그렇지 않다면 여전히 ‘ 여전히 재미있는 해킹입니다.
  • 답변

    xdelta 를 사용합니다.이 유형의 용도를 위해 만들어졌습니다. 최신 버전의 VCDIFF (RFC 3284)를 기반으로합니다.

    댓글

    • 링크가 작동하지 않습니다 (다른 URL이 있습니까?). 1) diff patch 파일을 계산하고 2) abc2를 복원하는 방법을 보여주기 위해 몇 줄에 예제를 추가 할 수도 있습니다. , abcpatch 만 주어 졌습니까?
    • 고정 URL
    • @vonbrand에게 감사드립니다. . 그러한 예가 있습니까?

    답변

    내 테스트에 따른 다른 답변 보완 :

    diff

    두 개의 매우 유사한 256MB 파일 abc 및 . 그런 다음 diff 파일을 만들어 보겠습니다.

    diff -ua abc abc2 > abc-abc2.diff 

    이제 abc2를 복구 해 보겠습니다. 원본 abc 파일 및 abc-abc2.diff :

    cp abc abc3 patch abc3 < abc-abc2.diff 

    또는

    cp abc abc3 patch abc3 -i abc-abc2.diff 

    또는

    patch abc -i abc-abc2.diff -o abc3 

    Linux에서 작동합니다. Windows에서도 시도했지만 (patch.exe 및 diff.exe도 사용할 수 있음) 알 수없는 이유로 실패했습니다. 생성 된 abc3 파일은 256MB 대신 1KB에 불과합니다 (I ” 이 답변은 나중에 여기에서 업데이트합니다).

    rsync

    허용 된 답변에 자세히 설명 된대로 다음과 같이 작동합니다.

    rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3 

    rdiff

    에 자세히 설명 됨 답변 , 이것도 해결책입니다.

    rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3 

    여기 에서 작동합니다.

    댓글

    • ‘ CONTROL을 만나면 파일 끝을 알리는 ” 텍스트 ” 모드에서 입력 파일을 읽고 있었기 때문에 Windows에서 패치가 실패했습니다. 입력 파일의 -Z (바이트 0x18). 이것은 디렉토리에 길이가 기록되지 않았던 초기 DOS 시대의 레거시 모드입니다. 파일 길이는 512 바이트 섹터 수를 기반으로 계산되었습니다. 바이너리 모드에서 파일을 열도록 patch에 지시 할 수 있다면 ‘이 오류가 없어야합니다.

    답글 남기기

    이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다