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

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

我有一个文件instructions.txt,内容如下:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

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

答案1

一行代码将 32 位的 1 和 0 字符串转换为相应的二进制:

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

答案2

添加-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  ....

答案3

我的原始答案不正确 —无法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'- 将给定值从十进制(十进制)格式化为十六进制(十六进制)
  • xxd -r -p- 反转(-r)普通转储(-p)- 从十六进制到原始二进制

Python:

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
  • 未引用的定界符( << 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(...)- 打印

答案4

二进制文件不使用换行符来分隔行。二进制文件没有分隔符;它只是一个包含一堆 0 和 1 的文件,存储在由文件分配表或类似映射控制的扇区中,以赋予它意义。

您可以将文本文件按原样转换为二进制,得到 192 位(24 字节),或者在每个 32 位序列后添加一个换行符,使文件具有 6 个额外字节。

下面的代码按照要求为您提供一个 192 位文件:

for x in $(cat file.txt); 
do s=${x:0:32}; 
echo $(printf '%08X' "$((2#$s))"); 
done | xxd -r -p > file.bin

如果不想使用额外的代码进行填充,另一种方法是一次读取 8 位(文本文件中的 4 字节行)

在 Ubuntu 16.04.7 上测试

相关内容