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()))
我在哪里弄错了方向?
答案 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