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

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) 

上面的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 

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

 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')) 

也不要使用variables名称,如stringfile而这些名称是模块或函数的名称。

编辑@汤姆

是的,非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) 

这个问题有一个更简单的解决scheme。

你只需要添加一个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) 

你不能序列化一个Python 3'string'到字节而不需要转换成某种编码。

 outfile.write(plaintext.encode('utf-8')) 

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

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

 bytes("my data", "encoding") 

例如:

 bytes("attack at dawn", "utf-8") 

返回的对象将与outfile.write

从py2切换到py3时,通常会发生此问题。 在py2 plaintext是一个string和一个字节数组types。 在py3 plaintext中只有一个stringoutfile.write()方法在outfile以二进制模式打开时实际上需要一个字节数组 ,所以会引发一个exception。 将input更改为plaintext.encode('utf-8')以解决问题。 如果这让你感到困扰,请继续阅读。

在py2中,file.write 声明使得它看起来像你传递了一个string: file.write(str) 。 实际上,你传递的是一个字节数组,你应该像这样读取声明: file.write(bytes) 。 如果你这样读,问题很简单, file.write(bytes)需要一个字节types,并且在py3中将字节从你转换的str中取出:

 py3>> outfile.write(plaintext.encode('utf-8')) 

为什么py2文件声明file.write带了一个string? 在py2中,声明的区别并不重要,因为:

 py2>> str==bytes #str and bytes aliased a single hybrid class in py2 True 

py2的str-bytes类有一些方法/构造函数,它们在某些方面performance得像一个string类,而在另一些方面则是一个字节数组类。 方便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 

py3为什么打破这个好系统? 那么因为在py2中,基本的string函数并不适用于世界其他地方。 衡量一个非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 

所有这一次,你认为你是在py2中要求一个string的len ,你从编码中获得字节数组的长度。 这个含糊不清的问题是双职class的根本问题。 您实施哪个版本的方法调用?

好消息是py3修复了这个问题。 它解开了str字节类。 str类具有类似string的方法,单独的bytes类具有字节数组方法:

 py3>> len('¡ok') #string 3 py3>> len('¡ok'.encode('utf-8')) #bytes 4 

希望知道这有助于使这个问题变得神秘化,并使迁徙的痛苦变得容易一些。

 >>> s = bytes("s","utf-8") >>> print(s) b's' >>> s = s.decode("utf-8") >>> print(s) s 

好吧,如果有用的情况下去除烦人的'b'字符。如果任何人有更好的主意,请build议我或随时编辑我在这里任何时间。我只是新手

对于django.test.TestCaseunit testing中的Django ,我改变了我的Python2语法:

 def test_view(self): response = self.client.get(reverse('myview')) self.assertIn(str(self.obj.id), response.content) ... 

要使用Python3 .decode('utf8')语法:

 def test_view(self): response = self.client.get(reverse('myview')) self.assertIn(str(self.obj.id), response.content.decode('utf8')) ...