【问题标题】:Python how to write to a binary file?Python如何写入二进制文件?
【发布时间】:2013-08-24 09:22:24
【问题描述】:

我有一个整数字节列表,类似于

[120, 3, 255, 0, 100]

如何将此列表作为二进制文件写入文件?

这行得通吗?

newFileBytes = [123, 3, 255, 0, 100]
# make file
newFile = open("filename.txt", "wb")
# write to file
newFile.write(newFileBytes)

【问题讨论】:

  • 你问“这行得通吗?”。你试过了吗?
  • 应该是TypeError: argument 1 must be string or buffer, not list

标签: python


【解决方案1】:

使用struct.pack 将整数值转换为二进制字节,然后写入字节。例如

newFile.write(struct.pack('5B', *newFileBytes))

但是我永远不会给二进制文件一个 .txt 扩展名。

这种方法的好处是它也适用于其他类型,例如,如果任何值大于 255,您可以使用 '5i' 作为格式而不是获取完整的 32 位整数。

【讨论】:

  • .txt 如果您有办法知道您正在写入的数据都在可打印的 ascii 范围内,那么它就可以了。但是,我认为在这种情况下您是正确的,因为示例数据包含不可打印的字符。
  • @Perkins 我没有假设这些值在 ASCII 范围内甚至会小于 256。即使是这样,.txt 文件也应该保留给那些对人类有意义的文件,而这些文件永远不会适用于二进制数据。
  • 你说得对,如果你要写入值大于 255 的数据,struct.pack 也是可行的方法,因为 bytearray 和 chr 都不能处理更大的整数值。
  • @MarkRansom:嗯,这绝对是解决“我有一个任意但固定大小的整数列表,如何将它们写入二进制文件? "我可以看到人们搜索那个问题并找到这个问题……
  • struct.pack 是更好的答案;它比简单地创建一个字节数组要灵活得多。
【解决方案2】:

这正是bytearray 的用途:

newFileByteArray = bytearray(newFileBytes)
newFile.write(newFileByteArray)

如果您使用的是 Python 3.x,则可以改用 bytes(并且可能应该这样做,因为它更好地表明了您的意图)。但在 Python 2.x 中,这是行不通的,因为 bytes 只是 str 的别名。像往常一样,使用交互式解释器显示比使用文本解释更容易,所以让我这样做。

Python 3.x:

>>> bytearray(newFileBytes)
bytearray(b'{\x03\xff\x00d')
>>> bytes(newFileBytes)
b'{\x03\xff\x00d'

Python 2.x:

>>> bytearray(newFileBytes)
bytearray(b'{\x03\xff\x00d')
>>> bytes(newFileBytes)
'[123, 3, 255, 0, 100]'

【讨论】:

  • 很好地使用内置类型。请注意,bytearray 是在 2.6 中添加的,如果要支持遗留系统,则应避免使用。
  • @Perkins:当然,如果您需要使用 2.3,您应该避免使用生成器表达式,如果您需要使用 2.2,请注意 str.encodestruct.pack。但是 2.6 已经推出 5 年了;仍然支持所有三个 Ubuntu LTS,支持所有三个 OS X 版本,以前的 CentOS/RHEL 主要版本等,都内置了它。如果你需要支持 2.5 或 2.1 或 1.6 或其他什么,你可能知道……
  • 在 Windows 上使用 Python 2,我发现写一个bytearray 仍然会将\n 转换为\r\n,这对于二进制数据来说是不令人满意的,如果打开时没有传递“b”标志文件。
  • @feersum:当然;这就是 2.x 中二进制与文本模式 的含义 的含义。你的字节来自什么类型并不重要。 (当然,在 3.x 中,二进制与文本模式意味着您编写字节与 unicode,\r\n 功能是文本通用换行选项的一部分。)
  • 我不确定 bytearray() 是文件写入的好选择。您需要将大小限制为可管理的块。否则,一旦文件大小过高,您将耗尽内存。
【解决方案3】:

要将小于 256 的整数转换为二进制,请使用 chr 函数。因此,您正在考虑执行以下操作。

newFileBytes=[123,3,255,0,100]
newfile=open(path,'wb')
newfile.write((''.join(chr(i) for i in newFileBytes)).encode('charmap'))

【讨论】:

  • 你的意思一定是
  • 不,我的意思是 charmap 而不是ascii,并且适用于python2 和python3。 ascii 编码仅适用于 python2。
【解决方案4】:

您可以使用以下代码示例使用 Python 3 语法:

from struct import pack
with open("foo.bin", "wb") as file:
  file.write(pack("<IIIII", *bytearray([120, 3, 255, 0, 100])))

这里是shell单行:

python -c $'from struct import pack\nwith open("foo.bin", "wb") as file: file.write(pack("<IIIII", *bytearray([120, 3, 255, 0, 100])))'

【讨论】:

    【解决方案5】:

    从 Python 3.2+ 开始,您还可以使用 to_bytes 本机 int 方法完成此操作:

    newFileBytes = [123, 3, 255, 0, 100]
    # make file
    newFile = open("filename.txt", "wb")
    # write to file
    for byte in newFileBytes:
        newFile.write(byte.to_bytes(1, byteorder='big'))
    

    即,在这种情况下,对to_bytes 的每次调用都会创建一个长度为 1 的字符串,其字符以大端顺序排列(对于长度为 1 的字符串来说是微不足道的),它表示整数值 byte .您还可以将最后两行缩短为一行:

    newFile.write(''.join([byte.to_bytes(1, byteorder='big') for byte in newFileBytes]))
    

    【讨论】:

      【解决方案6】:

      使用pickle,像这样:import pickle

      您的代码如下所示:

      import pickle
      mybytes = [120, 3, 255, 0, 100]
      with open("bytesfile", "wb") as mypicklefile:
          pickle.dump(mybytes, mypicklefile)
      

      要读回数据,请使用 pickle.load 方法

      【讨论】:

      • 这不会生成 5 字节长度的二进制文件,其中唯一的内容是 120、3、255、0、100。不过在封闭系统中,这可能是可以接受的。
      【解决方案7】:

      方便的函数将 int 数组写入文件,

      def write_array(fname,ray):
          '''
          fname is a file pathname
          ray is an array of int
          '''
          print("write:",fname)
          EncodeInit()
          buffer = [ encode(z) for z in ray ]
          some = bytearray(buffer)
          immutable = bytes(some)
          with open(fname,"wb") as bfh:
              wc = bfh.write(immutable)
              print("wrote:",wrote)
          return wc
      

      如何调用函数,

      write_array("data/filename",[1,2,3,4,5,6,7,8])
      

      并将以下内容包装在一个类中以进行可读编码/解码:

      Encode = {}
      Decode = {}
      def EncodeInit():
          '''
          Encode[] 0:62 as 0-9A-Za-z
          Decode[] 0-9A-Za-z as 0:62
          '''
          for ix in range( 0,10): Encode[ix] = ix+ord('0')
          for ix in range(10,36): Encode[ix] = (ix-10)+ord('A')
          for ix in range(36,62): Encode[ix] = (ix-36)+ord('a')
          for ix in range( 0,10): Decode[ix+ord('0')] = ix
          for ix in range(10,36): Decode[(ix-10)+ord('A')] = ix
          for ix in range(36,62): Decode[(ix-36)+ord('a')] = ix
      
      def encode(x):
          '''
          Encode[] 0:62 as 0-9A-Za-z
          Otherwise '.'
          '''
          if x in Encode: return Encode[x]
          # else: error
          return ord('.')
      
      def decode(x):
          '''
          Decode[] 0-9A-Za-z as 0:62
          Otherwise -1
          '''
          if x in Decode: return Decode[x]
          # else: error
          return -1
      

      【讨论】:

        猜你喜欢
        • 2017-06-30
        • 1970-01-01
        • 2014-01-07
        • 2012-12-25
        • 1970-01-01
        • 2022-01-04
        • 1970-01-01
        相关资源
        最近更新 更多