Open()命令缓冲区手动缓冲区操作不起作用

时间:2018-01-12 23:15:02

标签: python

我目前正在使用Raspberry Pi创建数据记录功能,我不确定是否发现了一个小错误。我使用的代码如下:

import sys, time, os

_File = 'TemperatureData1.csv'
_newDir = '/home/pi/Documents/Temperature Data Logs'
_directoryList = os.listdir(_newDir)

os.chdir(_newDir)

# Here I am specifying the file, that I want to write to it, and that
# I want to use a buffer of 5kb
output = open(_File, 'w', 5000)

try:
    while (1):
    output.write('hi\n')
    time.sleep(0.01)

except KeyboardInterrupt:
    print('Keyboard has been pressed')
    output.close()
    sys.exit(1)

我发现当我定期查看创建的文件属性时,文件大小会根据默认缓冲区设置8192字节增加,而不是我指定的5kb。但是,当我在Python 2.7.13中运行完全相同的程序时,缓冲区大小会根据请求变为5kb。

我想知道是否有其他人有过这方面的想法并且对于使程序在Python 3.6.3上运行的解决方案有什么想法?提前致谢。我可以在python 2.7.13上解决这个问题,这是我纯粹的好奇心导致我发布这个问题。

2 个答案:

答案 0 :(得分:1)

Python在版本2中对open的定义就是您所使用的:

  

open(name[, mode[, buffering]])

在Python 3中,open命令略有不同,因为buffering不是位置整数,而是关键字arg:

  

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

docs有以下注释:

  

buffering是一个可选的整数,用于设置缓冲策略。通过0关闭缓冲关闭(仅允许二进制模式),1选择行缓冲(仅在文本模式下可用),以及整数> 1表示固定大小的块缓冲区的大小(以字节为单位)。如果没有给出缓冲参数,则默认缓冲策略的工作方式如下:

     

二进制文件以固定大小的块缓冲;使用启发式方法选择缓冲区的大小,尝试确定底层设备的“块大小”并回退到io.DEFAULT_BUFFER_SIZE。在许多系统上,缓冲区通常为4096或8192字节长。   “交互式”文本文件(isatty()返回True的文件)使用行缓冲。其他文本文件使用上述策略用于二进制文件。

那个特殊的8192号码只是2 ^ 13。

我建议您尝试buffering=5000

答案 1 :(得分:1)

我做了更多的研究,并设法找到了为什么要设置缓冲'如果值大于1,则不会在python 3或更高版本中手动将缓冲区操作为所需的大小(字节)。

这似乎是因为io库在处理文件,文本缓冲区和二进制缓冲区时使用了两个缓冲区。当处于文本模式时,根据文本缓冲区刷新文件(当缓冲> 1时似乎不能操作该文件缓冲区)。相反,缓冲参数操纵二进制缓冲区,然后将其提供给文本缓冲区,因此缓冲函数不适用于程序员期望的方式。这在以下链接中进一步解释:

https://bugs.python.org/issue30718

然而,有一种解决方法;你需要在二进制模式而不是文本模式下使用open(),然后使用io.TextIOWrapper函数使用二进制缓冲区写入txt或csv文件。解决方法如下:

 import sys, time, os, io

_File = 'TemperatureData1.csv'

# Open or overwrite the file _file, and use a 20kb buffer in RAM
# before data is saved to disk.
output = open(_File, mode='wb', buffering=700)
output = io.TextIOWrapper(output, write_through=True)

try:
    while (1):
        output.write('h\n')
        time.sleep(0.01)

except KeyboardInterrupt:
    print('Keyboard has been pressed')
    output.close()
    sys.exit(1)