簡體   English   中英

如何在Python 3中將文本流編碼為字節流?

[英]How to encode a text stream into a byte stream in Python 3?

將字節流解碼為文本流很容易:

import io
f = io.TextIOWrapper(io.BytesIO(b'Test\nTest\n'), 'utf-8')
f.readline()

在此示例中, io.BytesIO(b'Test\\nTest\\n')是字節流, f是文本流。

我想做的恰恰相反。 給定文本流或類文件對象,我想將其編碼為字節流或類文件對象, 而不處理整個流

這是我到目前為止所嘗試的:

import io, codecs

f = codecs.getreader('utf-8')(io.StringIO('Test\nTest\n'))
f.readline()
# TypeError: can't concat str to bytes

f = codecs.EncodedFile(io.StringIO('Test\nTest\n'), 'utf-8')
f.readline()
# TypeError: can't concat str to bytes

f = codecs.StreamRecoder(io.StringIO('Test\nTest\n'), None, None,
                         codecs.getreader('utf-8'), codecs.getwriter('utf-8'))
# TypeError: can't concat str to bytes

f = codecs.encode(io.StringIO('Test\nTest\n'), 'utf-8')
# TypeError: utf_8_encode() argument 1 must be str, not _io.StringIO

f = io.TextIOWrapper(io.StringIO('Test\nTest\n'), 'utf-8')
f.readline()
# TypeError: underlying read() should have returned a bytes-like object, not 'str'

f = codecs.iterencode(io.StringIO('Test\nTest\n'), 'utf-8')
next(f)
# This works, but it's an iterator instead of a file-like object or stream.

f = io.BytesIO(io.StringIO('Test\nTest\n').getvalue().encode('utf-8'))
f.readline()
# This works, but I'm reading the whole stream before converting it.

我正在使用Python 3.7

你可以很容易地自己寫這個; 你只需要決定如何進行緩沖。

例如:

class BytesIOWrapper(io.RawIOBase):
    def __init__(self, file, encoding='utf-8', errors='strict'):
        self.file, self.encoding, self.errors = file, encoding, errors
        self.buf = b''
    def readinto(self, buf):
        if not self.buf:
            self.buf = self.file.read(4096).encode(self.encoding, self.errors)
            if not self.buf:
                return 0
        length = min(len(buf), len(self.buf))
        buf[:length] = self.buf[:length]
        self.buf = self.buf[length:]
        return length
    def readable():
        return True

我認為這正是你所要求的。

>>> f = BytesIOWrapper(io.StringIO("Test\nTest\n"))
>>> f.readline()
b'Test\n'
>>> f.readline()
b'Test\n'
>>> f.readline()
b''

如果你想變得更聰明,你可能想要包裝一個codecs.iterencode而不是一次緩沖4K。 或者,因為我們正在使用緩沖區,您可能想要創建BufferedIOBase而不是RawIOBase 另外,一個名為BytesIOWrapper的類可能應該處理write ,但這很容易。 困難的部分是實現seek / tell ,因為你不能在TextIOBase任意尋求; 尋求開始和結束很容易; 另一方面,尋求知道以前的位置很難(除非你依賴TextIOBase.tell返回一個字節位置 - 它不能保證這樣做,而且,盡管TextIOWrapper確實如此, StringIO不會......)。

無論如何,我認為這是如何編寫即使是最復雜的io類的最簡單的演示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM