จำเป็นต้องอ่านทุก ๆ ไบต์เพื่อตรวจสอบว่าไฟล์ที่คัดลอกนั้นเหมือนต้นฉบับหรือไม่?


16

ฉันเพิ่งเรียนรู้เกี่ยวกับโปรแกรมที่เรียกว่า Total Commander เป็นการแทนที่ Windows Explorer และมีของตัวเองเพื่อคัดลอกไฟล์ ในการตรวจสอบว่าไฟล์เหมือนกันหรือไม่แทนที่จะคำนวณ CRC จะตรวจสอบทุกไบต์อย่างแท้จริงทีละตัวทั้งบนต้นฉบับและสำเนา

คำถามของฉันคือ: จำเป็นหรือไม่ CRC หรือเทคนิคอื่นใดผิดพลาดหรือไม่ ในฐานะโปรแกรมเมอร์คุณควรลองใช้ระบบที่สมบูรณ์แบบ แต่ช้าหรือสุดยอดมากเกินไปหรือไม่?


3
ดูว่า "rsync" จัดการกับสิ่งนี้อย่างไร

21
การคำนวณ CRCs (หรือดีกว่า sha1sums) ในไฟล์ทั้งสองนั้นจำเป็นต้องอ่านทุกไบต์ หากคุณทำการเปรียบเทียบแบบเป็นไบต์ต่อไบต์คุณสามารถออกได้ทันทีที่คุณเห็นข้อมูลไม่ตรงกัน - และคุณไม่ต้องกังวลเกี่ยวกับไฟล์สองไฟล์ที่แตกต่างกันซึ่งมีการตรวจสอบแบบเดียวกัน . ในทางกลับกันการตรวจสอบการเปรียบเทียบมีประโยชน์เมื่อคุณเปรียบเทียบไฟล์ที่ไม่ได้อยู่ในเครื่องเดียวกัน สามารถคำนวณ checksums ในพื้นที่และคุณไม่จำเป็นต้องถ่ายโอนเนื้อหาทั้งหมดผ่านเครือข่าย
Keith Thompson

3
ในฐานะที่เป็นโอกาสของการปะทะกันถ้าคุณใช้กัญชาที่ดีเช่นsha1sumคุณสวยมากไม่ต้องกังวลเกี่ยวกับเรื่องนี้เว้นแต่มีคนจงใจและราคาแพงสร้างไฟล์ที่มี sha1sums ชน ฉันไม่มีแหล่งที่มาสำหรับเรื่องนี้ แต่ฉันได้ยิน (ในบริบทของ git) ว่าความน่าจะเป็นของไฟล์ที่แตกต่างกันสองไฟล์ที่มี sha1sum เดียวกันนั้นมีความน่าจะเป็นของสมาชิกทุกคนในทีมพัฒนาของคุณที่ถูกกินโดย หมาป่า ในวันเดียวกัน ในเหตุการณ์ที่ไม่เกี่ยวข้องอย่างสมบูรณ์
Keith Thompson

5
@KeithThompson: ผมคิดว่าการแสดงความคิดเห็นครั้งแรกของคุณควรจะเป็นคำตอบ :-)
คณบดีฮาร์ดิ้ง

6
คำตอบสั้น ๆ - ไม่ดีที่สุดเพียงให้คอมพิวเตอร์ทำเพื่อคุณ
psr

คำตอบ:


40

การคำนวณ CRCs (หรือดีกว่า sha1sums) ในไฟล์ทั้งสองนั้นจำเป็นต้องอ่านทุกไบต์ หากคุณทำการเปรียบเทียบแบบไบต์ต่อไบต์คุณสามารถออกได้ทันทีที่คุณเห็นข้อมูลไม่ตรงกัน - และคุณไม่ต้องกังวลเกี่ยวกับไฟล์สองไฟล์ที่แตกต่างกันซึ่งมีการตรวจสอบเดียวกัน (แม้ว่าจะไม่น่าจะหายไปสำหรับ sha1sum) . ดังนั้นหากคุณทำการเปรียบเทียบแบบโลคัลการเปรียบเทียบแบบไบต์ต่อไบต์จะเร็วกว่าการเปรียบเทียบค่า checksum อย่างน้อย (เว้นแต่คุณจะคำนวณค่า checksums อยู่แล้ว)

ในทางกลับกันการตรวจสอบการเปรียบเทียบมีประโยชน์เมื่อคุณเปรียบเทียบไฟล์ที่ไม่ได้อยู่ในเครื่องเดียวกัน สามารถคำนวณ checksums ในพื้นที่และคุณไม่จำเป็นต้องถ่ายโอนเนื้อหาทั้งหมดผ่านเครือข่าย

วิธีไฮบริดยังเป็นไปได้ ตัวอย่างเช่นคุณอาจคำนวณและเปรียบเทียบ checksums ของไฟล์สองไฟล์ต่อครั้งซึ่งสามารถหลีกเลี่ยงการอ่านไฟล์ทั้งหมด ( หากแตกต่างกัน) ขณะเดียวกันก็หลีกเลี่ยงการส่งไฟล์ทั้งหมดผ่านเครือข่าย โปรโตคอล rsyncทำอะไรเช่นนี้

โปรดทราบว่าการใช้ซีอาร์ซีแบบง่ายช่วยให้คุณมีโอกาสปะทะกันอย่างรุนแรงดังที่ Dave Rager พูดถึงในคำตอบของเขา ใช้อย่างน้อย sha1sum หรือแม้แต่สิ่งที่ใหม่กว่า (อย่าพยายามคิดค้นอัลกอริทึมการแปลงแป้นพิมพ์ของคุณเองผู้ที่พัฒนา sha1sum รู้เรื่องนี้มากกว่าเราคนใดคนหนึ่ง)

ในฐานะที่เป็นโอกาสของการปะทะกันถ้าคุณใช้กัญชาดีเช่น sha1sum คุณสวยมากไม่ต้องกังวลเกี่ยวกับเรื่องนี้เว้นแต่มีคนจงใจและราคาแพงสร้างไฟล์ที่มี sha1sums ชน (สร้างการชนกันดังกล่าวไม่เป็นไปได้เมื่อครั้งแรกที่ผมเขียนนี้ แต่กำลังดำเนินการอยู่ ) เธซเธฑสกอตต์ Chacon ของ "โปร Git" , ส่วนที่ 6.1 :

ต่อไปนี้เป็นตัวอย่างเพื่อให้คุณทราบถึงสิ่งที่จะได้รับการชน SHA-1 หากมนุษย์ 6.5 พันล้านคนบนโลกเขียนโปรแกรมและทุก ๆ วินาทีแต่ละคนก็สร้างรหัสที่เทียบเท่ากับประวัติเคอร์เนลของลินุกซ์ทั้งหมด (1 ล้านวัตถุ Git) และผลักมันลงในที่เก็บ Git อันยิ่งใหญ่มันใช้เวลา 5 ปีจนกระทั่ง ที่เก็บนั้นมีวัตถุมากพอที่จะมีโอกาส 50% ของการชนกันของวัตถุ SHA-1 เดียว มีความเป็นไปได้สูงกว่าที่สมาชิกทีมงานเขียนโปรแกรมของคุณทุกคนจะถูกโจมตีและสังหารโดยหมาป่าในเหตุการณ์ที่ไม่เกี่ยวข้องในคืนเดียวกัน

สรุป :

การเปรียบเทียบแบบไบต์ต่อไบต์นั้นดีสำหรับการเปรียบเทียบในท้องถิ่น sha1sum นั้นดีสำหรับการเปรียบเทียบจากระยะไกลและไม่มีโอกาสที่จะเกิดผลบวกปลอม


ควรสังเกตว่าคำจำกัดความทั่วไปของฟังก์ชันแฮช "ดี" รวมถึงคุณสมบัติที่ยากมากในการสร้างอินพุตที่แตกต่างกันด้วยแฮชเดียวกัน ("ความต้านทานการชน") SHA-1 มีจุดอ่อน (ตามทฤษฏี) ในแง่นี้ แต่คุณไม่สามารถ "สร้างไฟล์สองไฟล์ที่ชนกัน" แม้ว่าคุณจะพยายามอย่างหนัก
sleske

@sleske: อัปเดต
Keith Thompson

1
@ KeithThompson ฉันตอบคำถามได้ แต่ฉันคิดว่าถึงเวลาสำหรับการอัพเดท SHA1 - The SHAppening
K.Steff

ฉันสงสัยว่าพวกเขาจะบ้าๆบอ ๆ ถ้าคุณพยายามโฮสต์ repo เชิงทฤษฎีนี้ใน GitHub
hBy2Py

1
ฉันหมายถึงว่าพวกเขาจะไม่มีความสุขที่มี exabytes จำนวนมากต่อวินาทีของข้อมูลผลักพวกเขา :-)
hBy2Py

10

นี่เป็นอีกวิธีในการคิดเกี่ยวกับมัน

หากไม่มีความเป็นไปได้ที่ไฟล์สองไฟล์ที่แตกต่างกันจะมีซีอาร์ซีที่เหมือนกันดังนั้นการขยายก็หมายความว่าทุกไฟล์สามารถแสดงด้วยซีอาร์ซีที่เป็นเอกลักษณ์หากซีอาร์ซีมีขนาดเล็กกว่าไฟล์ต้นฉบับ ถ้าไม่เช่นนั้นคุณจะต้องทำการเปรียบเทียบไฟล์ต้นฉบับเนื่องจากคุณจะเปรียบเทียบจำนวนไบต์เดียวกัน

ในทางทฤษฎีคุณสามารถใช้การบีบอัดแบบไม่สูญเสียข้อมูลทั้งสองด้านของการเปรียบเทียบเพื่อลดจำนวนไบต์ที่จำเป็นในการเปรียบเทียบ แต่มันเป็นเรื่องที่ทำผิดพลาดเพราะคุณต้องเสียวงจรมากขึ้นและต้องอ่านทุกไบต์ของไฟล์ทั้งสองเพื่อทำการบีบอัด . นั่นคือการเข้ารหัสทุกไบต์ (และตามลำดับ) ในรูปแบบการบีบอัดแบบไม่สูญเสียข้อมูลที่คุณต้องอ่านก่อนและเสียบเข้ากับอัลกอริทึมใช่ไหม? จบเกม.

นี่คือการเปรียบเทียบ:
หากคุณต้องการวิธีที่รวดเร็วในการพิจารณาว่าเอกสารที่พิมพ์สองฉบับนั้นเหมือนกันหรือไม่โดยเปรียบเทียบตัวอักษรเป็นตัวอักษรคุณสามารถเปรียบเทียบจำนวนตัวอักษรในแต่ละบรรทัดของเอกสารได้ หากการนับทั้งหมดตรงกันอัตราต่อรองจะดีขึ้นอย่างมากว่าเอกสารเหมือนกัน แต่ก็ไม่มีใครโต้แย้งได้ว่าคุณมั่นใจได้ว่าจดหมายทุกฉบับเหมือนกันโดยใช้วิธีการนี้


3

วิธีที่สมบูรณ์แบบเพียงวิธีเดียวในการตรวจสอบไฟล์ที่เหมือนกันคือไบต์สำหรับเปรียบเทียบไบต์ อีกวิธีที่จะเป็นการประมาณที่ยุติธรรมคือการคำนวณแฮชเช่น MD5 สำหรับไฟล์และเปรียบเทียบสิ่งเหล่านั้น เป็นไปได้ว่าอาจมีการชนกันของแฮช แต่อาจไม่น่าเป็นไปได้

ฉันคิดว่าไบต์สำหรับการเปรียบเทียบแบบไบต์จะเร็วกว่าการคำนวณแฮชของไฟล์ทั้งสองในเวลาที่คุณทำการเปรียบเทียบ อย่างไรก็ตามหากแอปพลิเคชันของคุณคำนวณแฮชและจัดเก็บ meta-data เกี่ยวกับไฟล์ของคุณล่วงหน้าการเปรียบเทียบแฮชจะเร็วขึ้นอย่างมาก

CRC อาจไม่ใช่วิธีที่จะไปเพราะเป็นเพียงกลไกตรวจจับข้อผิดพลาดไม่ใช่แฮช (หรือแฮชที่แย่ที่มีการชนกันมาก)


+1 เห็นด้วย มันมีโอกาสมากที่ฮาร์ดไดรฟ์ของคุณจะแตกเมื่อเทียบกับการชนกันของฟังก์ชั่นการแฮ็กที่ดี (CRC32 อ่อนแอ - เห็นด้วย)
MichałŠrajer

2

เพื่อให้แน่ใจว่า 100% ไฟล์สองไฟล์เหมือนกันคุณต้องตรวจสอบไบต์

ทำไม? Hash collision นั่นแหละทำไม! ขึ้นอยู่กับอัลกอริทึมที่ใช้สำหรับการแฮชการชนอาจมีมากหรือน้อย แต่ก็เป็นไปไม่ได้เลย ทำตามขั้นตอนเหล่านี้:

  1. ตรวจสอบขนาดไฟล์
  2. ตรวจสอบประเภท mime
  3. ตรวจสอบแฮช
  4. ตรวจสอบ offsets สุ่มและเปรียบเทียบบิต

จะทำให้คุณมั่นใจได้อย่างแน่นอนว่าไฟล์ทั้งสองเหมือนกัน แต่มีโอกาสน้อยมาก (มาก) ที่คุณมีการปะทะกันในมือของคุณ ตัวเลือกว่าคุณต้องการไปเปรียบเทียบกับไกลแค่ไหนจะถูกกำหนดโดยสถานการณ์


ฉันคิดว่าถ้าคุณเลือกอัลกอริทึมการแปลงแป้นพิมพ์ที่ดี 2 และ 4 จะไม่ให้คุณภาพ "เท่าเทียม" ที่เพิ่มขึ้นอย่างแท้จริง อาจเป็นสิ่งที่จำเป็นสำหรับแฮ็กที่อ่อนแอเช่นกัน
MichałŠrajer

1
-1 สิ่งนี้ไม่สมเหตุสมผล หากคุณเลือกอัลกอริทึมการแปลงแป้นพิมพ์ที่ดีขั้นตอนอื่นทั้งหมดนั้นไม่จำเป็น 1. และ 4. ถูกครอบคลุมโดยสิ่งที่แฮชทำแล้วและ 2. ไร้สาระ (ระบบไฟล์ส่วนใหญ่ไม่มีแม้แต่ความคิดของ "ประเภท MIME" และแม้ว่าพวกเขามีมันจะเพิ่มข้อมูลน้อยมาก)
sleske

@sleske ฉันกำลังพูดว่าแทนที่จะแบนไฟล์ hashing ซึ่งเป็นการดำเนินการที่เข้มข้นคุณสามารถทำการดำเนินการเบื้องต้นที่ไม่หนักมาก

ฉันเริ่มใหม่เพียง 1 และ 3 ก็สมเหตุสมผลแล้ว (1) จะตั้งค่าสถานะกรณีส่วนใหญ่ของไฟล์ที่แตกต่างกันซึ่งไม่จำเป็นต้องคำนวณแฮช การแฮชการแฮชในไฟล์ความยาวเท่ากันนั้นไม่น่าที่จะกังวล
Michael Shaw

1

อย่างที่คนอื่น ๆ บอกกันว่ามันเร็วกว่าที่จะทำการเปรียบเทียบแบบไบต์ต่อไบต์ถ้าไฟล์สองไฟล์อยู่ในระบบเดียวกัน หากคุณกำลังพยายามเปรียบเทียบไฟล์หลาย ๆ ไฟล์คุณจะไปถึงจุดที่แฮ็คเป็นคำตอบที่ดีกว่าถ้าไฟล์อยู่ในที่จัดเก็บข้อมูลแบบหมุน

การแฮ็ชส่องสว่างจริง ๆ เมื่อคุณไม่มีข้อมูลทั้งหมดที่พร้อมใช้งาน ตัวอย่างเช่นไฟล์ที่อยู่ในเครื่องที่แตกต่างกัน นอกจากนี้ยังให้คุณบันทึกผลลัพธ์ของการคำนวณและอ้างอิงในภายหลัง (รายงานนี้เหมือนกับรายงานเก่าหรือไม่เมื่อคุณจัดทำรายงานจะบันทึกแฮชของมันไว้เมื่อคุณทำรายงานฉบับต่อไปคุณสามารถเปรียบเทียบแฮชได้ไม่เพียง แต่คุณไม่จำเป็นต้องอ่านฉบับเก่าในตัวคุณเอง ' ไม่จำเป็นต้องมีสำเนาของมันไว้ด้วย)


0

ฉันคิดว่าคุณควรใช้ยูทิลิตีการเปรียบเทียบไฟล์ที่ให้มากับระบบปฏิบัติการของคุณหรือใช้เครื่องมือเปรียบเทียบไฟล์ (ดู: เครื่องมือเปรียบเทียบไฟล์วิกิ ) เพื่อเปรียบเทียบเนื้อหาหลังจากคุณตรวจสอบคุณสมบัติไฟล์ที่ระบุโดย @Glenn Nelson

ฉันไม่คิดว่า CRC นั้นถูกต้อง 100% และฉันคิดว่าความแม่นยำนั้นลดลงตามความยาวของไฟล์ นอกจากนี้ฉันไม่แนะนำให้คุณเขียนตั้งแต่ต้นเนื่องจากอาจต้องมีการทดสอบมากมาย


0

จำเป็นต้องอ่านทุก ๆ ไบต์เพื่อตรวจสอบว่าไฟล์ที่คัดลอกนั้นเหมือนต้นฉบับหรือไม่? ใช่แน่นอน 100%

จำเป็นต้องอ่านทุก ๆ ไบต์เพื่อตรวจสอบว่าไฟล์ที่คัดลอกนั้นไม่เหมือนกับต้นฉบับหรือไม่? NO

ดังนั้นในการกำหนดไม่ใช่ identicality อย่างรวดเร็วเมตรวจสอบครั้งแรกเช่นขนาดไฟล์และการตรวจสอบใด ๆ หรือซีอาร์ซี MIME ประเภท / ว่า OS / ระบบไฟล์ / ร้านอาจอยู่แล้วจะยังคงรักษา เนื่องจากระบบดังกล่าวได้รับการคำนวณล่วงหน้าคุณจึงไม่ต้องจ่ายค่าใช้จ่ายนี้ในขณะทำการเปรียบเทียบ

หากการทดสอบนั้นผ่านไปคุณยังคงต้องเปรียบเทียบทุก ๆ ไบต์ถ้าคุณต้องการความแน่นอน 100% แต่ต้องทราบว่าในซีพียูที่มี pipelined ที่ทันสมัยและการใช้หลายเธรดและโปรเซสเซอร์ / ซีพียูหลายตัวการทำการบล็อกไฟล์ขนาดใหญ่นั้นรวดเร็ว และมีประสิทธิภาพเพราะกระบวนการสามารถขนานได้อย่างมาก. วิธีเร็วกว่าการคำนวณทางคณิตศาสตร์ประเภทใด ๆ ที่เกี่ยวข้องกับแต่ละไบต์ (แม้ว่าอัลกอริทึมบางตัวอาจเป็นแบบขนานกันได้ แต่อาจจะไม่ง่ายเลย นั่นเป็นเพราะซีพียูที่ถูกวางท่อสามารถทำการเปรียบเทียบบล็อกของหน่วยความจำในไมโครโค้ดหรือแม้กระทั่งฮาร์ดแวร์ (เร็วมาก) และระบบย่อยของดิสก์ต่อหน่วยความจำได้รับการปรับให้เหมาะสมที่สุดในการนำไฟล์ขนาดใหญ่ไปยัง / จากหน่วยความจำ ฮาร์ดแวร์. หากแอปพลิเคชันของคุณทำสิ่งนี้เป็นประจำและเป็นคอขวดของประสิทธิภาพที่ทราบกันดีคุณควรใช้สิ่งนี้ในโค้ดแบบมัลติเธรดที่เขียนขึ้นอย่างดีซึ่งใช้ประโยชน์จากระบบปฏิบัติการของคุณและฮาร์ดแวร์ที่ขนานกัน (อาจใช้ภาษาที่ออกแบบมาสำหรับ นี้).

เฉพาะในกรณีที่คุณต้องการประมวลผลแต่ละไฟล์หนึ่งครั้งและทำการเปรียบเทียบหลาย ๆ ครั้งในภายหลัง (ซึ่งคุณจำ ["แคช"] ข้อมูลสรุปหรือ "บีบอัด" [ตามที่ JohnFX ใส่ไว้] ผลการวิเคราะห์) จะมีประโยชน์อย่างมากต่อการทำเช่นนั้น และจากนั้นเพียงเพื่อพิสูจน์ความแตกต่าง (มีแนวโน้ม); เพื่อพิสูจน์ความเหมือนกันคุณยังคงต้องทำการเปรียบเทียบแบบไบต์ต่อไบต์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.