TypeError:'str'不支持缓冲区接口

Fut*_*ing 263 python string gzip

plaintext = input("Please enter the text you want to compress")
filename = input("Please enter the desired filename")
with gzip.open(filename + ".gz", "wb") as outfile:
    outfile.write(plaintext) 
Run Code Online (Sandbox Code Playgroud)

上面的python代码给出了以下错误:

Traceback (most recent call last):
  File "C:/Users/Ankur Gupta/Desktop/Python_works/gzip_work1.py", line 33, in <module>
    compress_string()
  File "C:/Users/Ankur Gupta/Desktop/Python_works/gzip_work1.py", line 15, in compress_string
    outfile.write(plaintext)
  File "C:\Python32\lib\gzip.py", line 312, in write
    self.crc = zlib.crc32(data, self.crc) & 0xffffffff
TypeError: 'str' does not support the buffer interface
Run Code Online (Sandbox Code Playgroud)

Mic*_*las 292

如果使用Python3x,那么string它与Python 2.x的类型不同,则必须将其转换为字节(对其进行编码).

plaintext = input("Please enter the text you want to compress")
filename = input("Please enter the desired filename")
with gzip.open(filename + ".gz", "wb") as outfile:
    outfile.write(bytes(plaintext, 'UTF-8'))
Run Code Online (Sandbox Code Playgroud)

也不要使用变量名,例如,string或者file那些是模块或函数的名称.

编辑@Tom

是的,非ASCII文本也被压缩/解压缩.我使用UTF-8编码的波兰语字母:

plaintext = 'Polish text: ?????ó????????Ó???'
filename = 'foo.gz'
with gzip.open(filename, 'wb') as outfile:
    outfile.write(bytes(plaintext, 'UTF-8'))
with gzip.open(filename, 'r') as infile:
    outfile_content = infile.read().decode('UTF-8')
print(outfile_content)
Run Code Online (Sandbox Code Playgroud)


use*_*849 96

这个问题有一个更简单的解决方案.

您只需要t在模式中添加一个即可wt.这会导致Python将文件作为文本文件而不是二进制文件打开.一切都会好起来的.

完整的程序变为:

plaintext = input("Please enter the text you want to compress")
filename = input("Please enter the desired filename")
with gzip.open(filename + ".gz", "wt") as outfile:
    outfile.write(plaintext)
Run Code Online (Sandbox Code Playgroud)

  • 添加"t"可能会产生副作用.在Windows上编码为文本的文件将换行符("\n")转换为CRLF("\ r \n"). (15认同)
  • 它适用于python 3不仅3.4 (3认同)
  • 这绝对是正确的答案!所有其他人都非常难看...... (3认同)

小智 42

您无法将Python 3'字符串'序列化为字节,而无需将explict转换为某些编码.

outfile.write(plaintext.encode('utf-8'))
Run Code Online (Sandbox Code Playgroud)

可能是你想要的.这也适用于python 2.x和3.x.


Sku*_*del 28

对于Python 3.x,您可以通过以下方式将文本转换为原始字节:

bytes("my data", "encoding")
Run Code Online (Sandbox Code Playgroud)

例如:

bytes("attack at dawn", "utf-8")
Run Code Online (Sandbox Code Playgroud)

返回的对象将起作用outfile.write.


Ria*_*zvi 9

从py2切换到py3时,通常会发生此问题.在py2 plaintext中,它既是字符串又是字节数组类型.在py3 plaintext中只是一个字符串,并且该方法在二进制模式下打开时outfile.write()实际上采用了一个字节数组outfile,因此引发了异常.更改输入以plaintext.encode('utf-8')解决问题.如果这困扰你,请继续阅读.

在py2中,file.write的声明使它看起来像你传入一个字符串:file.write(str).实际上你传入一个字节数组,你应该一直在阅读这样的声明:file.write(bytes).如果你喜欢这个问题是简单的读它,file.write(bytes)需要一个字节型和PY3得到字节走出了一条海峡,你把它转换:

py3>> outfile.write(plaintext.encode('utf-8'))
Run Code Online (Sandbox Code Playgroud)

为什么py2 docs声明file.write了一个字符串?在py2中,声明的区别并不重要,因为:

py2>> str==bytes         #str and bytes aliased a single hybrid class in py2
True
Run Code Online (Sandbox Code Playgroud)

py2 的str-bytes类具有方法/构造函数,使其在某些方面表现得像字符串类,在其他方面表现为字节数组类.方便file.write不是吗?:

py2>> plaintext='my string literal'
py2>> type(plaintext)
str                              #is it a string or is it a byte array? it's both!

py2>> outfile.write(plaintext)   #can use plaintext as a byte array
Run Code Online (Sandbox Code Playgroud)

为什么py3打破了这个不错的系统?好吧因为在py2中,基本的字符串函数不适用于世界其他地方.使用非ASCII字符测量单词的长度?

py2>> len('¡no')        #length of string=3, length of UTF-8 byte array=4, since with variable len encoding the non-ASCII chars = 2-6 bytes
4                       #always gives bytes.len not str.len
Run Code Online (Sandbox Code Playgroud)

这段时间你以为你在py2 中要求输入一个字符串的len,你从编码中得到了字节数组的长度.这种含糊不清是双重课程的根本问题.您实现了哪个版本的方法调用?

好消息是py3修复了这个问题.它解开了strbytes类.的STR类有绳状的方法中,单独的字节类具有字节阵列方法:

py3>> len('¡ok')       #string
3
py3>> len('¡ok'.encode('utf-8'))     #bytes
4
Run Code Online (Sandbox Code Playgroud)

希望知道这有助于解决问题,并使迁移的痛苦更容易承受.