BytesIO.truncate方法不扩展缓冲区内容

时间:2019-12-17 12:19:43

标签: python bytesio

IOBase.truncate方法的文档中说:

  

truncate(size = None)

     

将流的大小调整为给定的字节大小(如果未指定大小,则调整为当前位置)。当前流的位置不变。调整大小可以扩展或减小当前文件的大小。在扩展的情况下,新文件区域的内容取决于平台(在大多数系统上,其他字节为零填充)。返回新的文件大小。

     

在版本3.5中进行了更改:Windows现在在扩展时将文件填充为零。

因此,考虑到这一点,我假设BytesIO(这是BufferedIOBase的子类,而该子类又是IOBase的子类)在此方法执行完之后会更改其内部缓冲区大小被呼叫。

但是下面的代码片段表明我的假设是错误的:

from io import BytesIO

# prints b'\x00\x00\x00\x00\x00\x00\x00\x00'
data = BytesIO(8 * b"\x00")
print(data.getvalue())

# prints 16
print(data.truncate(16))

# prints b'\x00\x00\x00\x00\x00\x00\x00\x00'
print(data.getvalue())

# prints b'\x00\x00\x00\x00\x00\x00\x00\x00'
print(bytes(data.getbuffer()))

我在哪里弄错了方向?

1 个答案:

答案 0 :(得分:2)

检查source code,看来该文档不是最新的BytesIO实现:

static PyObject *_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size)
/*[clinic end generated code: output=9ad17650c15fa09b input=423759dd42d2f7c1]*/
{
    CHECK_CLOSED(self);
    CHECK_EXPORTS(self);

    if (size < 0) {
        PyErr_Format(PyExc_ValueError,    
                     "negative size value %zd", size);
        return NULL;
    }

    if (size < self->string_size) {    
        self->string_size = size;    
        if (resize_buffer(self, size) < 0)    
            return NULL;   
    }

    return PyLong_FromSsize_t(size);

}

if (size < self->string_size)测试可确保如果大小大于先前的大小,则什么也不做。

我的猜测是,对于真正的文件处理程序,truncate的工作方式类似于基础平台(扩展文件),但不适用于内存映射处理程序。

如果我们知道对象将要失败,则可以通过在对象的末尾编写代码来简单地模拟所需的行为:

def my_truncate(data,size):
    current_size = len(data.getvalue())
    if size < current_size:
        return data.truncate(size)
    elif size == current_size:
        return size  # optim
    else:
        # store current position
        old_pos = data.tell()
        # go to end
        data.seek(current_size)
        # write zeroes
        data.write(b"\x00" * (size-current_size))
        # restore previous file position
        data.seek(old_pos)
        return size