Python 类型错误:';str';不支持缓冲区接口 plaintext=input(“请输入要压缩的文本”) filename=输入(“请输入所需的文件名”) 以gzip.open(文件名+“.gz”,“wb”)作为输出文件: outfile.write(纯文本)

Python 类型错误:';str';不支持缓冲区接口 plaintext=input(“请输入要压缩的文本”) filename=输入(“请输入所需的文件名”) 以gzip.open(文件名+“.gz”,“wb”)作为输出文件: outfile.write(纯文本),python,string,gzip,Python,String,Gzip,上面的python代码给了我以下错误: 回溯(最近一次呼叫最后一次): 文件“C:/Users/Ankur-Gupta/Desktop/Python_-works/gzip_-work1.py”,第33行,在 压缩字符串() 文件“C:/Users/Ankur Gupta/Desktop/Python_works/gzip_work1.py”,第15行,压缩字符串 outfile.write(纯文本) 写入文件“C:\Python32\lib\gzip.py”,第312行 self.crc=zl

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

回溯(最近一次呼叫最后一次):
文件“C:/Users/Ankur-Gupta/Desktop/Python_-works/gzip_-work1.py”,第33行,在
压缩字符串()
文件“C:/Users/Ankur Gupta/Desktop/Python_works/gzip_work1.py”,第15行,压缩字符串
outfile.write(纯文本)
写入文件“C:\Python32\lib\gzip.py”,第312行
self.crc=zlib.crc32(数据,self.crc)&0xffffffff
TypeError:“str”不支持缓冲区接口

如果不将Python 3“字符串”明确转换为某些编码,则无法将其序列化为字节

outfile.write(纯文本.encode('utf-8'))

这可能是你想要的。这同样适用于python 2.x和3.x。对于python 3.x,您可以通过以下方式将文本转换为原始字节:

bytes("my data", "encoding")
例如:

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

返回的对象将使用
outfile.write

如果使用Python3x,则
string
与Python2.x的类型不同,必须将其强制转换为字节(编码)

当变量名是模块或函数名时,也不要使用变量名,如
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)

这个问题有一个更容易的解决办法

您只需在模式中添加一个
t
,使其成为
wt
。这会导致Python将文件作为文本文件而不是二进制文件打开。然后一切都会好起来的

完整的程序如下所示:

plaintext=input(“请输入要压缩的文本”)
filename=输入(“请输入所需的文件名”)
以gzip.open(文件名+“.gz”,“wt”)作为输出文件:
outfile.write(纯文本)

如果有人有更好的主意,请建议我或随时在这里编辑我。我只是
Django.test.TestCase
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'))
    ...

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

在py2中,字符串使它看起来像是传入了一个字符串:
file.write(str)
。实际上,您正在传入一个字节数组,您应该像这样读取声明:
file.write(bytes)
。如果您这样阅读,问题很简单,
file.write(bytes)
需要一个bytes类型,在py3中,要从str中获取字节,您需要转换它:

py3>> outfile.write(plaintext.encode('utf-8'))
为什么py2文档声明
file.write
使用字符串?在py2中,声明的区别并不重要,因为:

py2>> str==bytes         #str and bytes aliased a single hybrid class in py2
True
py2的str bytes类具有方法/构造函数,这些方法/构造函数在某些方面使其行为类似于字符串类,在另一些方面使其行为类似于字节数组类。方便
文件。写
不是吗

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中,基本的字符串函数不适用于世界其他地方。使用非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中字符串的len,您是在从编码中获得字节数组的长度。这种模糊性是双重责任阶级的根本问题。您实现了任何方法调用的哪个版本

好消息是py3解决了这个问题。它分离str和bytes类。str类具有类似字符串的方法,separate bytes类具有字节数组方法:

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

希望知道这一点有助于揭开问题的神秘面纱,让迁移的痛苦更容易承受

奇怪的是,这把它修好了;原始代码在3.1下为我工作,文档中的示例代码也没有显式编码。如果您在非ASCII文本上使用它,gunzip会解压缩它吗?我出错了。我用Unicode印地语输入了我的名字,它成功地用gzip压缩了它。我正在使用Python3。2@TomZych:可能与3.2中的更改有关:我用ActiveState Python 3.1和3.2测试了它。在我的机器上,它可以在两种模式下工作。对于文件压缩,您应该始终以二进制模式打开输入:您需要能够稍后解压缩文件并获得完全相同的内容。转换为Unicode(
str
)并返回是不必要的,并且有解码错误或输入与输出不匹配的风险。您也可以使用
s.encode('utf-8')
将python改为
s.decode('utf-8')
,以取代
s=bytes(“s”,“utf-8”)
它对python2也有效吗?这可能是一种让代码在python2和python3上运行的方法吗?哇,老兄,你真棒!谢谢让我投票支持你。这应该是公认的答案:)添加“t”可能会产生副作用。在windows上,编码为文本的文件将换行符(“\n”)转换为CRLF(“\r\n”)。@MikePennington:请解释为什么压缩文本没有用?
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
py3>> len('¡ok')       #string
3
py3>> len('¡ok'.encode('utf-8'))     #bytes
4