TypeError : 'str'은 버퍼 인터페이스를 지원하지 않습니다


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

위의 파이썬 코드는 다음과 같은 오류를 발생시킵니다.

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

1
@ MikePennington : 왜 텍스트 압축이 유용하지 않은지 설명하십시오.
galinette

답변:


295

Python3x를 사용하는 경우 stringPython 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'))

또한 같은 변수 이름을 사용하지 않는 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)

이것이 고정 된 것은 이상하다. 원래 코드는 3.1에서 저에게 효과적이며 문서의 샘플 코드도 명시 적으로 인코딩되지 않습니다. ASCII가 아닌 텍스트에 사용하면 gunzip이 압축을 해제합니까? 오류가 발생했습니다.
Tom Zych

유니 코드 힌디어로 내 이름을 입력하고 gzip으로 압축했습니다. 저는 Python 3.2를 사용하고 있습니다
Future King

@Tom Zych : 아마도 3.2의 변경 사항과 관련이있을 것입니다 : docs.python.org/dev/whatsnew/3.2.html#gzip-and-zipfile
Skurmedel

ActiveState Python 3.1 및 3.2로 테스트했습니다. 내 컴퓨터에서는 두 가지 모두에서 작동합니다.
Michał Niklas 2016 년

1
파일 압축의 경우 항상 입력을 이진 모드로 열어야합니다. 나중에 파일의 압축을 풀고 정확히 동일한 내용을 얻을 수 있어야합니다. 유니 코드 ( str)로 변환 하거나 다시 변환하는 것은 불필요하며, 디코딩 오류 또는 입력과 출력 간의 불일치 위험이 있습니다.
Alexis

96

이 문제에 대한 더 쉬운 해결책이 있습니다.

t모드 에 추가하기 만하면 됩니다 wt. 이로 인해 파이썬은 파일을 바이너리가 아닌 텍스트 파일로 엽니 다. 그러면 모든 것이 잘 작동합니다.

완전한 프로그램은 다음과 같습니다.

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)

python2에서도 작동합니까? python2 및 python3에서 코드를 작동시키는 방법 일 수 있습니까?
Loïc Faure-Lacroix

와우, 당신은 좋다! 감사! 투표 해 드리겠습니다. 이것은 허용 된 답변이어야합니다. :))
Loïc

15
"t"를 추가하면 부작용이있을 수 있습니다. Windows에서 텍스트로 인코딩 된 파일은 개행 ( ​​"\ n")을 CRLF ( "\ r \ n")로 변환합니다.
BitwiseMan

42

일부 인코딩으로의 변환없이 Python 3 'string'을 바이트로 직렬화 할 수 없습니다.

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

아마도 당신이 원하는 것입니다. 또한 이것은 Python 2.x 및 3.x 모두에서 작동합니다.


28

Python 3.x의 경우 다음을 통해 텍스트를 원시 바이트로 변환 할 수 있습니다.

bytes("my data", "encoding")

예를 들면 다음과 같습니다.

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

반환 된 객체는와 함께 작동합니다 outfile.write.


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)A가 필요 바이트 얻을 종류와 py3에를 바이트를 밖으로의 str을 당신이 그것을 변환 :

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

py2 docs가 왜 file.write문자열을 사용 한다고 선언 했습니까? py2에서 선언 구별은 중요하지 않았습니다.

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

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

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 이이 문제를 해결한다는 것입니다. strbytes 클래스를 분리합니다 . STR의 클래스를 갖는 문자열과 같은 방법의 개별 바이트 클래스 바이트 배열 방법이있다 :

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

이 점을 알면 문제를 이해하기 어렵고 마이그레이션 고통을 좀 더 쉽게 해결할 수 있습니다.


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

성가신 'b'문자를 제거하는 경우에 유용합니다. 누군가 더 나은 아이디어를 얻었 으면 언제든지 제안하거나 언제든지 편집 할 수 있습니다. 나는 초보자입니다.


s.encode('utf-8')s.decode('utf-8')s = bytes("s", "utf-8")
Hans Zimermann

4

의 경우 Djangodjango.test.TestCase단위 테스트, 내 변경 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'))
    ...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.