chuyển đổi tập tin văn bản của bit thành tập tin nhị phân


12

Tôi có một tập tin instructions.txtvới nội dung:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Làm cách nào tôi có thể tạo một tệp nhị phân instructions.bincó cùng dữ liệu với instructions.txt. Nói cách khác, .bintệp phải là 192 bit giống nhau trong .txttệp, với 32 bit trên mỗi dòng. Tôi đang sử dụng bash trên Ubuntu Linux. Tôi đã cố gắng sử dụng xxd -b instructions.txtnhưng đầu ra dài hơn 192 bit.

Câu trả lời:


6

oneliner để chuyển đổi các chuỗi 32 bit của các số và số 0 thành nhị phân tương ứng:

$ perl -ne 'print pack("B32", $_)' < instructions.txt > instructions.bin

Những gì nó làm:

  • perl -nesẽ lặp qua từng dòng tệp đầu vào được cung cấp trên STDIN ( instructions.txt)
  • pack("B32", $_)sẽ lấy danh sách chuỗi gồm 32 bit ( $_mà chúng ta vừa đọc từ STDIN) và chuyển đổi nó thành giá trị nhị phân (bạn có thể sử dụng thay thế "b32"nếu bạn muốn thứ tự bit tăng dần bên trong mỗi byte thay vì thứ tự bit giảm dần; xem perldoc -f packthêm chi tiết)
  • print sau đó sẽ xuất giá trị được chuyển đổi thành STDOUT, sau đó chúng tôi chuyển hướng đến tệp nhị phân của chúng tôi instructions.bin

kiểm chứng:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....

8

Thêm -rtùy chọn (chế độ đảo ngược) để xxd -bkhông thực sự hoạt động như dự định, vì xxd đơn giản là không hỗ trợ kết hợp hai cờ này (nó bỏ qua -bnếu cả hai được đưa ra). Thay vào đó, bạn phải tự chuyển đổi các bit thành hex. Ví dụ như thế này:

( echo 'obase=16;ibase=2'; sed -Ee 's/[01]{4}/;\0/g' instructions.txt ) | bc | xxd -r -p > instructions.bin

Giải thích đầy đủ:

  • Phần bên trong dấu ngoặc đơn tạo ra một bckịch bản. Đầu tiên, nó đặt cơ sở đầu vào thành nhị phân (2) và cơ sở đầu ra thành thập lục phân (16). Sau đó, sedlệnh in nội dung instructions.txtbằng dấu chấm phẩy giữa mỗi nhóm 4 bit, tương ứng với 1 chữ số hex. Kết quả được dẫn vào bc.
  • Dấu chấm phẩy là một dấu tách lệnh bc, vì vậy tất cả các tập lệnh thực hiện là in mọi số nguyên đầu vào ra sau (sau khi chuyển đổi cơ sở).
  • Đầu ra của bclà một chuỗi các chữ số hex, có thể được chuyển đổi thành một tệp với thông thường xxd -r -p.

Đầu ra:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018
$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....

Xin lỗi, vẫn còn một lỗi endianness trong này. Làm việc để sửa nó!
du mục

1
Trên thực tế, nó ổn. Tôi đã nhầm lẫn trước đó bằng cách sử dụng độ rộng đầu ra sai trong lệnh xxd cuối cùng.
du mục

1
Tôi đã thử kịch bản và nó hoạt động nhưng đầu ra : (standard_in) 1: syntax error. Bạn có thể giải thích những gì syntax errornó đang đề cập đến hoặc tại sao điều này xảy ra? Điều này cũng xảy ra trên máy của bạn?
dopamane

2

Câu trả lời ban đầu của tôi không chính xác - xxdkhông thể chấp nhận -phoặc -rvới -b...

Cho rằng các câu trả lời khác là hoàn toàn khả thi, và vì lợi ích của " cách khác ", làm thế nào về những điều sau đây:

Đầu vào

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

Đầu ra

$ hexdump -Cv < instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

Đường ống Bash:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - không cần thiết, nhưng được sử dụng cho rõ ràng
  • tr -d $'\n' - xóa tất cả các dòng mới từ đầu vào
  • read -N 4 nibble- đọc chính xác 4 × ký tự vào nibblebiến
  • printf '%x' "$((2#${nibble}))" chuyển đổi nibble từ nhị phân sang ký tự 1 × hex
    • $((2#...)) - chuyển đổi giá trị đã cho từ cơ sở 2 (nhị phân) sang cơ sở 10 (thập phân)
    • printf '%x' - định dạng giá trị đã cho từ cơ sở 10 (thập phân) sang cơ sở 16 (thập lục phân)
  • xxd -r -p- đảo ngược ( -r) một bãi chứa đơn giản ( -p) - từ hệ thập lục phân sang nhị phân thô

Con trăn

python << EOF > instructions.bin
d = '$(cat instructions.txt | tr -d $'\n')'
print(''.join([chr(int(d[i:i+8],2)) for i in range(0, len(d), 8)]))
EOF
  • Một heredoc ( << EOF) không được trích dẫn được sử dụng để đưa nội dung vào mã Python
    • Điều này không hiệu quả nếu đầu vào trở nên lớn
  • cattr- được sử dụng để có đầu vào sạch (một dòng)
  • range(0, len(d), 8)- nhận danh sách các số từ 0 đến cuối chuỗi d, bước 8 × ký tự một lần.
  • chr(int(d[i:i+8],2))- chuyển đổi lát cắt hiện tại ( d[i:i+8]) từ nhị phân sang thập phân ( int(..., 2)), sau đó chuyển sang ký tự thô ( chr(...))
  • [ x for y in z]- hiểu danh sách
  • ''.join(...) - chuyển đổi danh sách các ký tự thành một chuỗi
  • print(...) - in nó

1
Lưu ý: trong nhiều shell |ở cuối dòng hoạt động như dấu gạch chéo ngược: lệnh tiếp tục đến dòng tiếp theo. Bằng cách này bạn có thể thoát khỏi một vài dấu gạch chéo ngược. Tôi không chắc chắn nếu sử dụng các ký hiệu đường ống sau khi LF là quyết định sáng suốt của bạn. Tôi đang đề cập đến một cách khác trong trường hợp bạn không biết.
Kamil Maciorowski

1
Tôi không biết, cảm ơn! Tôi thực sự thích phá vỡ các đường ống thành các đường logic và có các đường ống |(hoặc chuyển hướng >, toán tử boolean &&, v.v ...) ở phía trước để hiển thị / rõ ràng ... có lẽ là một điều theo phong cách / sở thích.
Attie

1
Sau một vài suy nghĩ tôi có thể bắt đầu sử dụng phong cách này bởi vì người ta có thể nói hai dòng được kết nối, bằng cách kiểm tra bất kỳ trong số chúng. Nếu |ở cuối, dòng tiếp theo có thể trông giống như một lệnh độc lập, nó có thể gây nhầm lẫn. Đây là lý do tại sao tôi nghĩ rằng phong cách có thể là quyết định sáng suốt của bạn.
Kamil Maciorowski

Tuyệt vời, hãy cho tôi biết mọi chuyện diễn ra như thế nào :-)
Attie

1
Nó sẽ tốt thôi :)
Kamil Maciorowski

1

Bạn cũng có thể thử đăng bài này lên trang CodeGolf SE, nhưng đây là phiên bản Python thay thế của tôi (chỉ dành cho thử thách đá):

python -c "import sys,struct;[sys.stdout.buffer.write(struct.pack('!i',int(x,2)))for x in sys.stdin]" \
< input.txt > output.bin

Giả sử input.txtchứa dữ liệu của bạn và nó được định dạng thành 32 ký tự trên mỗi dòng.

Điều này sử dụng structgói Python 3 và viết / đọc để stdin / out. (Trong Python 2, nó sẽ ngắn hơn).

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.