将 io.StringIO 转换为 io.BytesIO

新手上路,请多包涵

原始问题: 我有一个 StringIO 对象,如何将它转换为 BytesIO

更新: 更普遍的问题是,如何在 python3 中将二进制(编码的) 类文件 对象转换为解码 的类文件 对象?

我得到的天真方法是:

 import io
sio = io.StringIO('wello horld')
bio = io.BytesIO(sio.read().encode('utf8'))
print(bio.read())  # prints b'wello horld'

有没有更有效和优雅的方式来做到这一点?上面的代码只是将所有内容读入内存,对其进行编码,而不是将数据分块流式传输。

例如,对于反向问题( BytesIO -> StringIO )存在一个类 - io.TextIOWrapper 正是这样做的(见这个 答案

原文由 ShmulikA 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 925
2 个回答

有趣的是,尽管这个问题看起来很合理,但要找出我需要将 StringIO 转换为 BytesIO 的实际原因并不容易。两者基本上都是缓冲区,您通常只需要其中一个就可以对字节或文本进行一些额外的操作。

我可能是错的,但我认为你的问题实际上是如何使用 BytesIO 实例,当你想要传递给它的某些代码需要一个文本文件时。

在这种情况下,这是一个常见问题,解决方案是 编解码器 模块。

使用它的两种常见情况如下:

编写要读取的文件对象

In [16]: import codecs, io

In [17]: bio = io.BytesIO(b'qwe\nasd\n')

In [18]: StreamReader = codecs.getreader('utf-8')  # here you pass the encoding

In [19]: wrapper_file = StreamReader(bio)

In [20]: print(repr(wrapper_file.readline()))
'qwe\n'

In [21]: print(repr(wrapper_file.read()))
'asd\n'

In [26]: bio.seek(0)
Out[26]: 0

In [27]: for line in wrapper_file:
    ...:     print(repr(line))
    ...:
'qwe\n'
'asd\n'

编写要写入的文件对象

In [28]: bio = io.BytesIO()

In [29]: StreamWriter = codecs.getwriter('utf-8')  # here you pass the encoding

In [30]: wrapper_file = StreamWriter(bio)

In [31]: print('жаба', 'цап', file=wrapper_file)

In [32]: bio.getvalue()
Out[32]: b'\xd0\xb6\xd0\xb0\xd0\xb1\xd0\xb0 \xd1\x86\xd0\xb0\xd0\xbf\n'

In [33]: repr(bio.getvalue().decode('utf-8'))
Out[33]: "'жаба цап\\n'"

原文由 newtover 发布,翻译遵循 CC BY-SA 4.0 许可协议

@foobarna 答案 可以通过继承一些 io 基类来改进

import io
sio = io.StringIO('wello horld')

class BytesIOWrapper(io.BufferedReader):
    """Wrap a buffered bytes stream over TextIOBase string stream."""

    def __init__(self, text_io_buffer, encoding=None, errors=None, **kwargs):
        super(BytesIOWrapper, self).__init__(text_io_buffer, **kwargs)
        self.encoding = encoding or text_io_buffer.encoding or 'utf-8'
        self.errors = errors or text_io_buffer.errors or 'strict'

    def _encoding_call(self, method_name, *args, **kwargs):
        raw_method = getattr(self.raw, method_name)
        val = raw_method(*args, **kwargs)
        return val.encode(self.encoding, errors=self.errors)

    def read(self, size=-1):
        return self._encoding_call('read', size)

    def read1(self, size=-1):
        return self._encoding_call('read1', size)

    def peek(self, size=-1):
        return self._encoding_call('peek', size)

bio = BytesIOWrapper(sio)
print(bio.read())  # b'wello horld'

原文由 imposeren 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题