1

我正在努力改进 Python 3.X 对PyFilesystem的支持。它是文件系统的抽象。每个文件系统对象都有一个 open 方法,该方法返回一个类似文件的对象。

我面临的问题是 open 方法适用open于 Python 2.X,但我希望它能够像io.open返回多个二进制或文本模式流之一一样工作。

我可以使用的是一种获取 Python 2.X 类文件对象的方法,并返回一个适当的 io 流对象,该对象读取/写入底层文件类对象(但如果需要处理缓冲/unicode 等)。

我在想类似以下的事情:

def make_stream(file_object, mode, buffering, encoding):
    # return a io instance

我看不到任何直接使用 stdlib 的方法。但它让我觉得 io 模块必须在后台做一些事情,因为它是一个提供缓冲/unicode 功能的软件层。

4

1 回答 1

1

Python 2 也包含相同的io

用于from io import open跨 Python 版本工作。

然后,您的 API 应该提供一个open()等效的(称为open()or make_stream()),它使用io类库来提供相同的功能。

您需要做的就是创建一个实现io.RawIOBaseABC的类,然后根据需要使用库提供的其他类来添加缓冲和文本处理:

import io

class MyFileObjectWrapper(io.RawIOBase):
    def __init__(self, *args):
        # do what needs done

    def close(self):
        if not self.closed:
            # close the underlying file
        self.closed = True

    # ... etc for what is needed (e.g. def read(self, maxbytes=None), etc.

def open(fileobj, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
    # Mode parsing and validation adapted from the io/_iomodule.c module
    reading, writing, appending, updating = False
    text, binary, universal = False

    for c in mode:
        if c == 'r':
            reading = True;
            continue
        if c == 'w':
            writing = True;
            continue
        if c == 'a':
            appending = True;
            continue
        if c == '+':
            updating = True;
            continue
        if c == 't':
            text = True;
            continue
        if c == 'b':
            binary = True;
            continue
        if c == 'U':
            universal = reading = True;
            continue
        raise ValueError('invalid mode: {!r}'.format(mode))

    rawmode = []
    if reading:   rawmode.append('r')
    if writing:   rawmode.append('w')
    if appending: rawmode.append('a')
    if updating:  rawmode.append('+')
    rawmode = ''.join(rawmode)

    if universal and (writing or appending):
        raise ValueError("can't use U and writing mode at once")

    if text and binary) {
        raise ValueError("can't have text and binary mode at once")

    if reading + writing + appending > 1:
        raise ValueError("must have exactly one of read/write/append mode")

    if binary
        if encoding is not None:
            raise ValueError("binary mode doesn't take an encoding argument")
        if errors is not None:
            raise ValueError("binary mode doesn't take an errors argument")
        if newline is not None:
            raise ValueError("binary mode doesn't take a newline argument")

    raw = MyFileObjectWrapper(fileobj)

    if buffering == 1:
        buffering = -1
        line_buffering = True
    else:
        line_buffering = False

    if buffering < 0:
        buffering = SOME_SUITABLE_DEFAULT

    if not buffering
        if not binary:
            raise ValueError("can't have unbuffered text I/O")

        return raw

    if updating:
        buffered_class = io.BufferedRandom
    elif writing or appending:
        buffered_class = io.BufferedWriter
    elif reading:
        buffered_class = io.BufferedReader

    buffer = buffered_class(raw, buffering)

    if binary:
        return buffer

    return io.TextIOWrapper(buffer, encoding, errors, newline, line_buffering)

上面的代码大部分是从Modules/_io/_iomodule.c io_open函数改编而来的,但是将原始文件对象替换为ABC的MyFileObjectWrapper子类。io.RawIOBase

于 2013-03-25T10:55:46.920 回答