6

在 Windows 中使用(或)权限打开的文件上的write()紧跟 a似乎不会更新文件。read()r+r+b

假设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.

这至少在 Linux 上运行良好。但是,当我在 Windows 上运行它时,消息会正确显示,但文件没有更改 - 就像write()被忽略了一样。如果我调用tell()文件句柄,则表明该位置已更新(在4之前write()8之后),但文件没有更改。

fd.seek(4)但是,如果我在该行之前添加一个明确的内容,write()那么一切都会按我的预期进行。

有人知道 Windows 下这种行为的原因吗?

作为参考,我在带有 NTFS 分区的 Windows 7 上使用 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

间接地添加 a 有flush()帮助,因为它使我看到描述类似问题的这篇文章。如果其中一位评论者是正确的,则它是底层 Windows C 库中的一个错误。

4

4 回答 4

6

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

引用 cplusplus 中的fopen 手册页fopen 页面

对于为追加而打开的文件(包含“+”号的文件),在这些文件上允许输入和输出操作,应在写入操作之后刷新(fflush)或重新定位(fseek、fsetpos、rewind)流读取操作或未到达文件末尾的读取操作,然后是写入操作。

所以总结一下,如果您需要在写入后读取文件,则需要fflush缓冲区,并且读取后的写入操作应该以a 开头fseek,如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;
}
于 2013-01-11T14:15:30.143 回答
2

这似乎是由于底层 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("----")

对于任何试图编写可移植代码的人来说,这可能是需要牢记的事情。

于 2013-01-11T14:19:45.867 回答
1

你试过冲洗吗?

fd.flush()

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

于 2013-01-11T14:04:48.097 回答
-1

实施是否有可能误解了“r+b”?Afaik "rb+" 用于二进制读写。

于 2013-01-11T14:02:34.060 回答