วิธีการย้อนกลับเนื้อหาของไฟล์ไบนารีหรือไม่


11

ฉันแก้ไขปัญหาที่ฉันพบไฟล์ข้อมูลที่ไม่มีนามสกุลไฟล์ คำสั่งแสดงให้เห็นว่ามันเป็นfile คำสั่งแสดงให้เห็นว่าผลิตภัณฑ์มวลรวมประชาชาติ ในบรรทัดสุดท้าย ดังนั้นหากฉันย้อนกลับไฟล์นี้จากนั้นฉันจะได้รับไฟล์ฟอร์แมต. PNGฉันค้นหาทุกที่ แต่ไม่พบวิธีการแก้ปัญหาที่อธิบายวิธีย้อนกลับเนื้อหาของไฟล์ไบนารีdata file (application/octet-stream)hd

คำตอบ:


11

ด้วยxxd(จากvim) และtac(จาก coreutils ของ GNU รวมถึงtail -rในบางระบบ):

< file.gnp xxd -p -c1 | tac | xxd -p -r > file.png

มีวิธีใด ๆ นี้จะนำมารวมกับvi.stackexchange.com/a/2237/10649 ? ฉันลองชุดค่าผสมทุกชนิดโดยไม่มีโชค :(
Iulian Onofrei

นี่ไม่ใช่วิธีแก้ปัญหาเนื่องจากมันจะทำมิเรอร์ไฟล์ทั้งหมด
ฟิลิปป์ Delteil

@PhilippeDelteil การทำมิเรอร์ไฟล์ทั้งหมดเป็นสิ่งที่ OP ขอมาที่นี่ คุณต้องการให้มันทำอะไรอีก?
Stéphane Chazelas

4

ในzsh(เชลล์เดียวที่สามารถจัดการกับข้อมูลไบนารีภายในได้ (เว้นแต่คุณต้องการพิจารณาวิธีการเข้ารหัส base64 ของ ksh93 )):

zmodload zsh/mapfile
(LC_ALL=C; printf %s ${(s::Oa)mapfile[file.gnp]} > file.png)
  • LC_ALL=C: อักขระเป็นไบต์
  • $mapfile[file.gnp]: เนื้อหาของfile.gnpไฟล์
  • s::: แยกสตริงออกเป็นส่วนประกอบของไบต์
  • Oa: reverse rder Oบนaเรย์ห้อยของอาร์เรย์นั้น

1
zshไม่ใช่เชลล์เท่านั้นที่สามารถจัดการข้อมูลไบนารี
fpmurphy

2

ksh93นี่เป็นวิธีหนึ่งของการย้อนกลับแฟ้มไบนารีใช้ ฉันทิ้งรหัส "หลวม" ไว้เพื่อให้เข้าใจง่ายขึ้น

#!/bin/ksh93

typeset -b byte

redirect 3< image.gpj || exit 1

eof=$(3<#((EOF)))

read -r -u 3 -N 1 byte
printf "%B" byte > image.jpg
3<#((CUR - 1))

while (( $(3<#) > 0 ))
do
    read -r -u 3 -N 1 byte
    printf "%B" byte >> image.jpg
    3<#((CUR - 2))
done

read -r -u 3 -N 1 byte
printf "%B" byte >> image.jpg

redirect 3<&- || echo 'cannot close FD 3'

exit 0

ดี นั่นเป็นคำตอบเดียวที่ไม่ได้เกี่ยวข้องกับการจัดเก็บไฟล์ทั้งหมดในหน่วยความจำ อย่างไรก็ตามมันไม่มีประสิทธิภาพอย่างมากในการที่มันจะทำการเรียกใช้ระบบหลาย ๆ ไฟล์สำหรับแต่ละไบต์ของไฟล์ (และการแปลงไปยัง / จาก base64) ดังนั้นจึงไม่เหมาะสำหรับไฟล์ที่ไม่เหมาะกับหน่วยความจำ ในเครื่องของฉันมันประมวลผลไฟล์ที่ประมาณ 10KB / s
Stéphane Chazelas

โปรดทราบว่าข้อความแรกreadข้างต้นไม่ควรอ่านอะไรเลยเมื่อเสร็จสิ้นไฟล์
Stéphane Chazelas

พยายามที่จะเข้าใจว่าทำไมมันถึงช้าขนาดนั้นฉันจึงลองใช้มันใต้straceและksh93ดูเหมือนว่าจะมีพฤติกรรมแปลก ๆ อย่างมากซึ่งมันค้นหาทั่วทุกที่ในไฟล์และอ่านจำนวนมากในเวลานั้น อาจแตกต่างจากgithub.com/att/ast/issues/15
Stéphane Chazelas

@ StéphaneChazelas ไม่มีความลึกลับว่าทำไมมันจึงค่อนข้างช้า ภายในลูปจะต้องค้นหาไปข้างหลังทุกครั้งที่อ่านไบต์ สิ่งนี้สามารถลดลงได้อย่างมากโดยปัจจัย 20 หรือมากกว่าโดยการอ่านและเขียนมากกว่าหนึ่งไบต์ในแต่ละครั้ง ด้านการเขียนของสิ่งต่าง ๆ สามารถปรับให้เหมาะสมเช่นเดียวกัน มีเทคนิคอื่น ๆ มากมายที่จะช่วยเร่งความเร็วของคุณ ฉันจะปล่อยให้การออกกำลังกายนั้นขึ้นอยู่กับคุณ
fpmurphy

ลองใช้straceสคริปต์เพื่อดูว่าฉันหมายถึงอะไร ksh93อ่านไฟล์หลายพันครั้ง ตัวอย่างเช่นก่อนที่จะอ่านไบต์แรกมันจะค้นหา 64KiB ที่ส่วนท้ายของไฟล์อ่าน 64KiB จากนั้นค้นหาก่อนไบต์สุดท้ายและอ่าน 1 ไบต์และทำสิ่งที่คล้ายกันสำหรับทุกไบต์ โปรดทราบว่าสิ่งที่คุณสามารถทำได้กับสตริงที่เข้ารหัส base64 นั้นมี จำกัด ดังนั้นหากคุณอ่านมากกว่าหนึ่งไบต์ในแต่ละครั้งมันจะเป็นการยากที่จะแยกแต่ละไบต์ของสิ่งนั้น
Stéphane Chazelas

2

ด้วย Perl:

perl -0777pe '$_=reverse $_'  [input_file]

การทดสอบประสิทธิภาพ:

dd if=/dev/urandom of=/tmp/a bs=1M count=1
LC_ALL=C tac -rs $'.\\|\n' /tmp/a > /tmp/r

time perl -0777pe '$_=reverse $_' /tmp/a         | diff -q - /tmp/r
time xxd -p -c1 /tmp/a | tac | xxd -p -r         | diff -q - /tmp/r
time perl -0777 -F -ape '$_=reverse@F' /tmp/a    | diff -q - /tmp/r
time LC_ALL=C tac -rs $'.\\|\n' /tmp/a           | diff -q - /tmp/r

ผลลัพธ์:

  • ผ่านการทดสอบในพื้นที่: โซลูชันของฉันเร็วที่สุดperl -0777 -Fคือช้าที่สุด
  • ผ่านการทดสอบกับลองออนไลน์! : ทางออกของฉันเร็วที่สุดxxdคือช้าที่สุด

หมายเหตุ: การdiffรันเวลาควรเหมือนกันสำหรับโซลูชันทั้งหมดเนื่องจากเอาต์พุตควรเหมือนกัน


1
ฉันได้ลบperlหนึ่งของฉัน ฉันไม่ได้ตระหนักในเวลานั้นreverseสามารถย้อนกลับสตริงได้เช่นกันดังนั้นการแยกที่ไม่เหมาะสมและเวอร์ชันของคุณดีกว่ามาก
Stéphane Chazelas

1

ฉันพยายามต่อไปนี้:

tac -rs '.' input.gnp > output.png

ความคิดคือการบังคับให้ 'แทค' โดยใช้ตัวละครใด ๆ เป็นตัวคั่น ฉันลองที่ไฟล์ไบนารีและดูเหมือนว่าจะทำงาน แต่การยืนยันใด ๆ ที่จะได้รับการชื่นชม

ข้อได้เปรียบหลักคือมันไม่ได้โหลดไฟล์ลงในหน่วยความจำ


ใช้งานไม่ได้สำหรับฉัน (ที่นี่พร้อม GNU tac8.28) เมื่ออินพุตมีอักขระขึ้นบรรทัดใหม่ printf '1\n2' | tac -rs . | od -vAn -tcเอาท์พุทแทน\n 2 1 2 \n 1คุณต้องการLC_ALL=Cหรือ.อาจจับคู่อักขระหลายไบต์
Stéphane Chazelas

4
LC_ALL=C tac -rs $'.\\|\n'ดูเหมือนว่าจะทำงาน
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.