看来,在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+b
和rb+
– 官方的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库中的一个错误。
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 +”用于读写二进制文件。