如何使用二进制文件。覆盖特定字节

时间:2018-10-30 10:17:27

标签: python python-3.x binaryfiles

我正在用python编写程序,并且希望能够写入二进制文件中的特定字节。我试图用一个小的二进制文件在外壳程序中执行此操作,该二进制文件包含数字0到15,但是我不知道该怎么做。下面是我刚进入shell并带有注释的代码,以演示我要执行的操作:

>>> File=open("TEST","wb") # Opens the file for writing.
>>> File.write(bytes(range(16))) # Writes the numbers 0 through 15 to the file.
16
>>> File.close() # Closes the file.
>>> File=open("TEST","rb") # Opens the file for reading, so that we can test that its contents are correct.
>>> tuple(File.read()) # Expected output: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
>>> File.close() # Closes the file.
>>> File=open("TEST","wb") # Opens the file for writing.
>>> File.seek(3) # Moves the pointer to position 3. (Fourth byte.)
3
>>> File.write(b"\x01") # Writes 1 to the file in its current position.
1
>>> File.close() # Closes the file.
>>> File=open("TEST","rb") # Opens the file for reading, so that we can test that its contents are correct.
>>> tuple(File.read()) # Expected output: (0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
(0, 0, 0, 1)
>>> File.close()
>>> File=open("TEST","wb") # I will try again using apend mode to overwrite.
>>> File.write(bytes(range(16)))
16
>>> File.close()
>>> File=open("TEST","ab") # Append mode.
>>> File.seek(3)
3
>>> File.write(b"\x01")
1
>>> File.close()
>>> File=open("TEST","rb")
>>> tuple(File.read()) # Expected output: (0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1)
>>> File.close()

我想要的输出如图所示,但是"wb"似乎擦除了文件中的所有数据,而"ab"不能向后查找。

在不重写整个文件的情况下如何实现所需的输出?

3 个答案:

答案 0 :(得分:5)

当您打开要用w写入的文件时,该文件被截断,所有内容均被删除。您需要打开文件以使用r+进行读写。从open()函数文档中:

  

'w'打开进行写操作,先截断文件

  

对于二进制读写访问,模式“ w + b”打开并将文件截断为0个字节。 “ r + b”打开文件时不会被截断。

因为文件已被首先截断,所以要定位到3,然后写\x01的前几个字节会用\x00来填充。

以追加模式打开文件通常仅限制对文件新部分的访问,因此前16个字节以外的任何内容都不能访问。再次,从文档中:

  

其他常用值是[...]和'a'用于附加(在某些Unix系统上,这意味着所有写操作都将附加到文件末尾,而与当前查找位置无关)。

在引用的章节中大胆强调)。这就是为什么尽管进行\x01调用,您的File.seek(3)字节仍在结尾处结束的原因。

r不会截断文件,而是使用seek()为您提供全部内容; r+将写访问权限添加到该模式。带有'r+b'的演示:

>>> with open('demo.bin', 'wb') as f:
...     f.write(bytes(range(16)))
...
16
>>> with open('demo.bin', 'rb') as f:
...     print(*f.read())
...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
>>> with open('demo.bin', 'r+b') as f:  # read and write mode
...     f.seek(3)
...     f.write(b'\x01')
...
3
1
>>> with open('demo.bin', 'rb') as f:
...     print(*f.read())
...
0 1 2 1 4 5 6 7 8 9 10 11 12 13 14 15

答案 1 :(得分:0)

如果我没记错的话,您必须在“附加模式”下打开文件,否则它将擦除所有内容并从头开始,然后在使用seek(3)时只需创建3个0,然后编写1.我将进一步研究如何直接写入职位,但您可能必须阅读整个文件,进行修改并再次写入整个文件。

您实际上可以在the documentation中了解有关此行为的信息:

  

'w'仅用于写入(具有相同名称的现有文件将被删除)

答案 2 :(得分:0)

解决方案是另一种模式:"r+b"。 (如其他答案所示。)

这是外壳中文件保留位置的解决方案:

>>> File=open("TEST","r+b") # Opens file for reading and writing.
>>> File.seek(3)
3
>>> File.write(b"\x01")
1
>>> File.close()
>>> File=open("TEST","rb")
>>> tuple(File.read()) # Expected output: (0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1)
(0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1)
>>> File.close()