Làm thế nào để đảo ngược nội dung của tệp nhị phân?


11

Tôi đã giải quyết một thử thách nơi tôi tìm thấy một tệp dữ liệu không có phần mở rộng tệp. Các filelệnh cho thấy nó là một data file (application/octet-stream). Các hdlệnh show GNP. trong dòng cuối cùng. Vì vậy, nếu tôi đảo ngược tệp này thì tôi sẽ nhận được tệp định dạng .PNG , tôi đã tìm kiếm ở mọi nơi nhưng tôi không tìm thấy giải pháp giải thích cách đảo ngược nội dung của tệp nhị phân.

Câu trả lời:


11

Với xxd(từ vim) và tac(từ lõi core GNU, cũng tail -rtrên một số hệ thống):

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

Có cách nào để kết hợp với vi.stackexchange.com/a/2237/10649 không? Tôi đã thử tất cả các loại kết hợp mà không gặp may mắn :(
Iulian Onofrei

Đây không phải là một giải pháp vì nó sẽ phản chiếu tất cả các tập tin.
Philippe Delteil

@PhilippeDelteil, phản chiếu tất cả các tập tin là những gì OP yêu cầu ở đây? Bạn muốn nó làm gì nữa?
Stéphane Chazelas

4

Trong zsh(lớp vỏ duy nhất có thể xử lý nội bộ dữ liệu nhị phân (trừ khi bạn muốn xem xét phương pháp mã hóa base64 của ksh93 )):

zmodload zsh/mapfile
(LC_ALL=C; printf %s ${(s::Oa)mapfile[file.gnp]} > file.png)
  • LC_ALL=C: ký tự là byte
  • $mapfile[file.gnp]: nội dung của file.gnptập tin
  • s::: chia chuỗi thành các thành phần byte của nó
  • Oa: Order ngược trên achỉ mục rray mảng đó

1
zshkhông phải là vỏ duy nhất có thể xử lý dữ liệu nhị phân.
fpmurphy

2

Đây là một cách để đảo ngược một tệp nhị phân bằng cách sử dụng ksh93. Tôi đã để lại mã "lỏng lẻo" để dễ hiểu hơn.

#!/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

đẹp. Đó là câu trả lời duy nhất cho đến nay không liên quan đến việc lưu trữ toàn bộ tệp trong bộ nhớ. Tuy nhiên, nó cực kỳ kém hiệu quả khi nó thực hiện một số cuộc gọi hệ thống cho mỗi byte của tệp (và chuyển đổi sang / từ cơ sở64), do đó, sẽ không phù hợp với các tệp không phù hợp với bộ nhớ. Trên máy của tôi, nó xử lý các tệp với tốc độ khoảng 10KB / giây
Stéphane Chazelas

Lưu ý rằng phần đầu tiên readở trên không nên đọc gì khi nó được thực hiện ở phần cuối của tệp.
Stéphane Chazelas

Cố gắng hiểu tại sao nó quá chậm, tôi đã thử chạy nó bên dưới straceksh93dường như đang cư xử rất kỳ lạ, nơi nó tìm kiếm khắp nơi trong tập tin và đọc số lượng lớn vào thời điểm đó. Có thể là một biến thể của github.com/att/ast/issues/15
Stéphane Chazelas

@ StéphaneChazelas. Không có bí ẩn tại sao nó tương đối chậm. Trong vòng lặp, nó phải tìm ngược lại mỗi lần nó đọc một byte. Điều này có thể dễ dàng giảm đáng kể theo hệ số 20 hoặc thậm chí nhiều hơn bằng cách đọc và viết nhiều hơn một byte mỗi lần. Mặt viết của mọi thứ có thể được tối ưu hóa tương tự. Rất nhiều kỹ thuật khác có sẵn để tăng tốc mọi thứ. Tôi sẽ để lại bài tập đó cho bạn.
fpmurphy

Hãy thử stracetrên kịch bản để xem những gì tôi có ý nghĩa. ksh93đọc các tập tin hàng ngàn lần. Chẳng hạn, trước khi đọc byte đầu tiên, nó tìm kiếm 64KiB ở cuối tệp, đọc 64KiB, sau đó tìm trước byte cuối cùng và đọc 1 byte và thực hiện một cái gì đó tương tự cho mỗi byte. Lưu ý rằng những gì bạn có thể làm với các chuỗi được mã hóa base64 đó bị hạn chế, vì vậy nếu bạn đọc nhiều hơn một byte cùng một lúc, sẽ khó khăn hơn để trích xuất từng byte riêng lẻ.
Stéphane Chazelas

2

Với perl:

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

Kiểm tra hiệu suất:

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

Kết quả:

  • Thử nghiệm tại địa phương: giải pháp của tôi là nhanh nhất, perl -0777 -Flà chậm nhất.
  • Đã thử nghiệm trên thử trực tuyến! : giải pháp của tôi là nhanh nhất, xxdlà chậm nhất.

Lưu ý: thời gian diffchạy phải giống nhau cho tất cả các giải pháp, vì đầu ra phải giống nhau.


1
Tôi đã xóa cái của tôi perl. Tôi đã không nhận ra vào thời điểm đó reversecũng có thể đảo ngược chuỗi, vì vậy, việc chia tách đó không có ý nghĩa gì nhiều và phiên bản của bạn tốt hơn nhiều.
Stéphane Chazelas

1

Tôi đã thử như sau:

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

Ý tưởng là buộc 'tac' sử dụng bất kỳ ký tự nào làm dấu phân cách. Tôi đã thử điều đó trên một tệp nhị phân và nó dường như hoạt động nhưng mọi xác nhận sẽ được đánh giá cao.

Ưu điểm chính là nó không tải tập tin vào bộ nhớ.


Không hoạt động đối với tôi (ở đây với GNU tac8.28) khi đầu vào chứa các ký tự dòng mới. printf '1\n2' | tac -rs . | od -vAn -tcđầu ra \n 2 1thay vì 2 \n 1. Bạn cũng cần LC_ALL=Choặc .có thể khớp các ký tự nhiều byte.
Stéphane Chazelas

4
LC_ALL=C tac -rs $'.\\|\n'dường như làm việc mặc dù.
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.