将文本的位文件转换为二进制文件


12

我有一个instructions.txt包含内容的文件:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

如何创建instructions.bin与相同数据的二进制文件instructions.txt。换句话说,.bin文件应与文件中的192位相同.txt,每行32位。我在Ubuntu Linux上使用bash。我试图使用,xxd -b instructions.txt但是输出的长度比192位长。

Answers:


6

oneliner将1和32的32位字符串转换为相应的二进制:

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

它能做什么:

  • perl -ne将遍历STDIN(instructions.txt)提供的输入文件的每一行
  • pack("B32", $_)将获取一个32位的字符串列表($_我们刚刚从STDIN读取),并将其转换为二进制值("b32"如果您想在每个字节中以升序而不是降序使用,则可以选择使用;perldoc -f pack有关更多详细信息,请参见)
  • print 然后将转换后的值输出到STDOUT,然后我们将其重定向到二进制文件 instructions.bin

校验:

$ 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

-r选项(反向模式)添加到xxd -b实际上并没有按预期方式工作,因为xxd根本不支持将这两个标志组合使用(-b如果同时给出了这两个标志,它将忽略)。相反,您必须先将这些位转换为十六进制。例如这样:

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

完整说明:

  • 括号内的部分将创建一个bc脚本。首先将输入基数设置为二进制(2),将输出基数设置为十六进制(16)。之后,该sed命令将instructions.txt在每组4位之间用分号打印内容,该位对应于1个十六进制数字。结果通过管道传输到中bc
  • 分号是中的命令分隔符bc,因此脚本所做的全部工作是打印出每个输入整数(在基本转换之后)。
  • 的输出bc是一个十六进制数字序列,可以使用通常的转换为文件xxd -r -p

输出:

$ 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  ....

抱歉,其中仍然存在字节序错误。正在修复它!
nomadictype '18 -10-10

1
其实很好。之前我在最后一个xxd命令中使用了错误的输出宽度,这使我感到困惑。
nomadictype '18 -10-10

1
我已经测试了脚本,它可以工作,但输出:(standard_in) 1: syntax error。您能解释syntax error它指的是什么或为什么会发生吗?这也会在您的计算机上发生吗?
dopamane '18 -10-10

2

原来的答案是不正确的- xxd不能接受任何-p-r-b...

鉴于其他答案是可行的,并且出于“ 另一种方式 ”的考虑,请执行以下操作:

输入值

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

输出量

$ 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

Bash管道:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat -不必要,但为清楚起见
  • tr -d $'\n' -从输入中删除所有换行符
  • read -N 4 nibble- 准确地将 4个字符读入nibble变量
  • printf '%x' "$((2#${nibble}))" 将半字节从二进制转换为1×十六进制字符
    • $((2#...)) -将给定值从2(二进制)转换为10(十进制)
    • printf '%x' -将给定值的格式从10进制(十进制)设置为16进制(十六进制)
  • xxd -r -p-反向(-r)普通转储(-p)-从十六进制到原始二进制

蟒蛇:

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
  • 未引用的heredoc<< EOF)用于将内容获取到Python代码中
    • 如果输入变大,则效率不高
  • cattr-用于获得干净的(单行)输入
  • range(0, len(d), 8)-获取从0到字符串末尾的数字列表d,一次步进8个字符。
  • chr(int(d[i:i+8],2))-将当前切片(d[i:i+8])从二进制转换为十进制(int(..., 2)),然后转换为原始字符(chr(...)
  • [ x for y in z]- 清单理解
  • ''.join(...) -将字符列表转换为单个字符串
  • print(...) -打印

1
注意:在许多shell中|,一行的末尾就像反斜杠一样工作:命令继续到下一行。这样,您可以摆脱一些反斜杠。我不确定在LF之后使用管道符号是否是您明智的决定。我要说的是另一种方式,以防您不知道。
卡米尔Maciorowski

1
我不知道,谢谢!我喜欢将管道分成逻辑行,并在最前面显式地放置管道|(或重定向>,布尔运算符&&等),以提高可见性/清晰度……也许是样式/偏好。
Attie

1
经过一番思考,我可能会开始使用这种样式,因为通过检查其中的任何一条,便可以分辨出两条线是否已连接。如果|在末尾,则下一行可能看起来像一个独立的命令,可能会造成混淆。这就是为什么我认为样式可能是您明智的决定。
卡米尔Maciorowski

太好了,让我知道它是怎么回事:-)
Attie


1

您也可以尝试将其发布到CodeGolf SE网站,但这是我的替代Python版本(仅用于反冲挑战):

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

假设input.txt包含您的数据,并且其格式设置为每行32个字符。

这使用Python 3 struct包并向stdin / out写入/读取。(在Python 2中,它会更短)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.