为什么一个文件对象刷新,而另一个没有?

时间:2012-09-27 17:52:11

标签: python file flush

我想要一个文件对象在写入数据时直接刷新文件,并写下这个:

class FlushingFileObject(file):
    def write(self,*args,**kwargs):
        return_val= file.write(self,*args,**kwargs)
        self.flush()
        return return_val

    def writelines(self,*args,**kwargs):
        return_val= file.writelines(self,*args,**kwargs)
        self.flush()
        return return_val

但有趣的是,当我写信给它时它没有刷新,所以我尝试了一些包括这个的东西:

class FlushingFileObject(object):
    def __init__(self,*args,**kwargs):
        self.file_object= file(*args,**kwargs)

    def __getattr__(self, item):
        return getattr(self.file_object,item)

    def write(self,*args,**kwargs):
        return_val= self.file_object.write(*args,**kwargs)
        self.file_object.flush()
        return return_val

    def writelines(self,*args,**kwargs):
        return_val= self.file_object.writelines(*args,**kwargs)
        self.file_object.flush()
        return return_val

冲洗。

为什么不将file子类化在这个实例中?

2 个答案:

答案 0 :(得分:9)

很棒的问题。

这是因为Python通过绕过Python级write方法并直接调用file来优化对write个对象的fputs的调用。

要了解这一点,请考虑:

$ cat file_subclass.py
import sys
class FileSubclass(file):
    def write(self, *a, **kw):
        raise Exception("write called!")
    writelines = write
sys.stdout = FileSubclass("/dev/null", "w")
print "foo"
sys.stderr.write("print succeeded!\n")
$ python print_magic.py
print succeeded!

从未调用write方法!

现在,当对象不是file的子类时,事情按预期工作:

$ cat object_subclass.py
import sys
class ObjectSubclass(object):
    def __init__(self):
        pass
    def write(self, *a, **kw):
        raise Exception("write called!")
    writelines = write
sys.stdout = ObjectSubclass()
print "foo"
sys.stderr.write("print succeeded!\n")
$ python object_subclass.py
Traceback (most recent call last):
  File "x.py", line 13, in <module>
    print "foo"
  File "x.py", line 8, in write
    raise Exception("write called!")
Exception: write called!

通过Python源代码挖掘,看起来罪魁祸首是PyFile_WriteString函数,由print语句调用,它检查被写入的对象是否是{的实例{1}},如果是,则绕过对象的方法并直接调用file

fputs

答案 1 :(得分:-1)

file.flush()的文档说:

请注意 flush()不一定将文件的数据写入磁盘。使用flush()后跟os.fsync()来确保这种行为。

我在没有os.fsync调用的情况下测试了第一个版本的FlushingFileObject。该文件没有刷新。插入os.fsync(self.fileno())文件后刷新。然后我删除了os.fsync调用,现在文件刷新了!我想可以肯定的是,os.fsync调用是必要的。