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: कृपया बताएं कि पाठ को संपीड़ित करना उपयोगी क्यों नहीं है?
गैलीनेट

जवाबों:


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जबकि जो मॉड्यूल या समारोह के नाम हैं।

EDIT @Tom

हां, गैर-एएससीआईआई पाठ भी संपीड़ित / विघटित है। मैं 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 के तहत मेरे लिए काम किया, और डॉक्स में नमूना कोड भी स्पष्ट रूप से एनकोड नहीं करता है। यदि आप इसे गैर-एएससीआईआई पाठ पर उपयोग करते हैं, तो क्या गुनज़िप इसे विघटित करता है? मुझे एक त्रुटि मिली।
टॉम ज़िक

मैंने अपना नाम यूनिकोड हिंदी में टाइप किया और इसे सफलतापूर्वक gzip में संकुचित कर दिया। मैं Python 3.2
Future King


मैंने इसे ActiveState Python 3.1 और 3.2 के साथ परीक्षण किया। मेरी मशीन पर यह दोनों में काम करता है।
माइकल निकल्स

1
फ़ाइल संपीड़न के लिए आपको हमेशा बाइनरी मोड में इनपुट खोलना चाहिए : आपको बाद में फ़ाइल को अनकैप करने में सक्षम होना चाहिए और ठीक उसी सामग्री को प्राप्त करना चाहिए। यूनिकोड ( str) और बैक में बदलना अनावश्यक है, और इनपुट और आउटपुट के बीच त्रुटियों को कम करने या बेमेल होने का जोखिम है।
एलेक्सिस

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 पर कोड काम करने का एक तरीका हो सकता है?
लोकेक फ्योर-लैक्रोसिक्स

वाह, यार तुम अच्छे हो! धन्यवाद! मुझे तुम वोट दो। यह स्वीकृत उत्तर होना चाहिए :))
Lo15c

15
"T" जोड़ने से साइड-इफेक्ट्स हो सकते हैं। पाठ के रूप में एन्कोड की गई खिड़कियों की फ़ाइलों में CRLF ("\ r \ n") में कनवर्ट की गई नई लाइनें ("\ n") होंगी।
बिटविंडमैन

42

आप कुछ एन्कोडिंग में रूपांतरण की खोज के बिना बाइट्स के लिए पायथन 3 'स्ट्रिंग' को अनुक्रमित नहीं कर सकते।

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

संभवतः वही है जो आप चाहते हैं। इसके अलावा यह अजगर 2.x और 3.x दोनों के लिए काम करता है।


28

पायथन 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)जरूरत है एक बाइट प्राप्त करने के लिए प्रकार और 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

Str-बाइट py2 के वर्ग तरीकों / कंस्ट्रक्टर्स है कि यह कुछ मायनों में एक स्ट्रिंग वर्ग और अन्य लोगों में एक बाइट सरणी वर्ग की तरह व्यवहार करना है। सुविधाजनक 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

यह सब समय आपने सोचा था कि आप पी 2 में एक स्ट्रिंग की लेन के लिए पूछ रहे थे , आपको एन्कोडिंग से बाइट सरणी की लंबाई मिल रही थी। यह अस्पष्टता दोहरे कर्तव्य वर्गों के साथ मूलभूत समस्या है। आप किसी भी विधि कॉल के किस संस्करण को लागू करते हैं?

अच्छी खबर यह है कि py3 इस समस्या को ठीक करता है। यह str और बाइट्स वर्गों को नापसंद करता है । 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

वैसे अगर आपके लिए उपयोगी है कष्टप्रद 'बी' चरित्र को हटाने में। यदि किसी को बेहतर विचार मिला तो कृपया मुझे सुझाव दें या मुझे यहां किसी भी समय संपादित करने के लिए स्वतंत्र महसूस करें। मैं सिर्फ नौसिखिया हूं


आप s.encode('utf-8')इसका उपयोग इतने पाइथोनिक के रूप s.decode('utf-8')में भी कर सकते हैंs = bytes("s", "utf-8")
हंस ज़िमरमन

4

के लिए Djangoमें django.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'))
    ...
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.