IOBase.truncate
方法的文档说:
截断(大小=无(
将流的大小调整为给定的大小(以字节为单位((如果未指定大小,则调整为当前位置(。当前流位置不会更改。此大小调整可以扩展或减小当前文件大小。在扩展的情况下,新文件区域的内容取决于平台(在大多数系统上,额外的字节是零填充的(。将返回新的文件大小。
在 3.5 版更改: Windows 现在在扩展时将零填充文件。
因此,考虑到这一点,我认为BytesIO
(这是BufferedIOBase
的子类,又是IOBase
的子类(在调用此方法后会更改其内部缓冲区大小。
但是下面的代码片段表明我的假设是错误的:
from io import BytesIO
# prints b'x00x00x00x00x00x00x00x00'
data = BytesIO(8 * b"x00")
print(data.getvalue())
# prints 16
print(data.truncate(16))
# prints b'x00x00x00x00x00x00x00x00'
print(data.getvalue())
# prints b'x00x00x00x00x00x00x00x00'
print(bytes(data.getbuffer()))
我哪里走错了路?
检查源代码,似乎文档与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