我正在用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"
不能向后查找。
在不重写整个文件的情况下如何实现所需的输出?
答案 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()