在Windows中的Python文件中混合使用read()和write()

看来,在Windows中以r+ (或r+b )权限打开的文件上的read() write()紧跟的write()不会更新文件。

假设当前目录中有一个文件testfile.txt ,其内容如下:

 This is a test file. 

我执行下面的代码:

 with open("testfile.txt", "r+b") as fd: print fd.read(4) fd.write("----") 

我希望代码打印This并更新文件的内容:

 This----a test file. 

至less在Linux上这工作得很好。 但是,当我在Windows上运行它时,消息显示正确,但文件没有被更改 – 就像write()被忽略。 如果我在文件句柄上调用tell() ,它会显示位置已经更新(在write()之前是4之后是8 ),但没有更改文件。

但是,如果我在write()行之前放置一个明确的fd.seek(4) ,那么一切都按照我所期望的那样工作。

有谁知道在Windows下这种行为的原因?

作为参考,我正在Windows 7上使用带有NTFS分区的Python 2.7.3。

编辑

为了回应评论,我尝试了r+brb+ – 官方的Python文档似乎暗示前者是规范的。

我把调用fd.flush()放在不同的地方,在read()write()之间放置一个像这样的:

 with open("testfile.txt", "r+b") as fd: print fd.read(4) fd.flush() fd.write("----") 

…产生以下有趣的错误:

 IOError: [Errno 0] Error 

编辑2

间接地,添加一个flush()帮助,因为它导致我这个职位描述类似的问题。 如果其中的评论者之一是正确的,这是基础Windows C库中的一个错误。

Solutions Collecting From Web of "在Windows中的Python文件中混合使用read()和write()"

Python的文件操作应遵循libc约定,在内部使用C文件IO函数实现。

从cplusplus的 fopen手册页或fopen页面引用

对于打开的附加文件(包括“+”号),允许输入和输出操作,流应该刷新(fflush)或重新定位(fseek,fsetpos,倒带)之间的写操作之间读操作或读操作没有到达文件结束,然后进行写操作。

所以总结一下,如果你需要在写入后读取一个文件,你需要fflush缓冲区,读取之后的一个写操作应该以fseek fd.seek(0, os.SEEK_CUR) ,如fd.seek(0, os.SEEK_CUR)

所以只需将您的代码片段更改为

 with open("test1.txt", "r+b") as fd: print fd.read(4) fd.seek(0, os.SEEK_CUR) fd.write("----") 

该行为与类似的C程序的行为是一致的

 #include <cstdio> int main() { char buffer[5] = {0}; FILE *fp = fopen("D:\\Temp\\test1.txt","rb+"); fread(buffer, sizeof(char), 4, fp); printf("%s\n", buffer); /*without fseek, file would not be updated*/ fseek(fp, 0, SEEK_CUR); fwrite("----",sizeof(char), 4, fp); fclose(fp); return 0; } 

看来,这是由于底层的Windows库(我个人认为是错误的)的行为,并没有错误的Python。 在阅读和写作之间添加一个flush()调用(这显然是一个很好的习惯 ),我得到了一个带有零errno的IOError ,这与本文中讨论的问题是一样的 。

从那篇文章中,我发现这个提到这个问题的Python问题 ,并且说seek()调用实际上是最好的解决方法,每次你从阅读到写入都改变了flush()

考虑到所有这一切,似乎编写上面的代码的最好的方法是在Windows上成功运行:

 with open("testfile.txt", "r+b") as fd: print fd.read(4) fd.flush() fd.seek(4) fd.write("----") 

任何试图编写可移植代码的人都可能需要记住这些事情。

你尝试过冲洗吗?

 fd.flush() 

它是依赖于操作系统的,因为写使用文件系统缓存机制

这个实现是否可能错误地解释了“r + b”? Afaik“rb +”用于读写二进制文件。