我有这样的代码:
f1 = open('file1', 'a')
f2 = open('file1', 'a')
f1.write('Test line 1\n')
f2.write('Test line 2\n')
f1.write('Test line 3\n')
f2.write('Test line 4\n')
当使用标准Python 2.7解释器运行此代码时,该文件包含预期的四行。但是,当我在PyPy下运行此代码时,该文件只包含两行。
在处理附加模式的文件时,有人能解释Python和PyPy之间的区别吗?
更新:PyPy 2.3中不存在这个问题。
答案 0 :(得分:3)
不同行为的原因是文件I / O操作的不同实现。
CPython implements它是来自fopen
的{{1}},fread
和fwrite
函数之上的文件I / O,正在使用stdio.h
流。
同时PyPy implements它是在POSIX FILE *
,open
和write
函数之上的文件I / O,并且正在使用read
文件描述符。
在C中比较这两个程序:
int
和
#include <stdio.h>
int main() {
FILE *a = fopen("file1", "a");
FILE *b = fopen("file1", "a");
fwrite("Test line 1\n", 12, 1, a);
fflush(a);
fwrite("Test line 2\n", 12, 1, b);
fflush(b);
fwrite("Test line 3\n", 12, 1, a);
fflush(a);
fwrite("Test line 4\n", 12, 1, b);
fclose(a);
fclose(b);
return 0;
}
有关#include <fcntl.h>
#include <unistd.h>
int main() {
int a = open("file1", O_CREAT | O_WRONLY | O_APPEND);
int b = open("file1", O_CREAT | O_WRONLY | O_APPEND);
write(a, "Test line 1\n", 12);
write(b, "Test line 2\n", 12);
write(a, "Test line 3\n", 12);
write(b, "Test line 4\n", 12);
close(a);
close(b);
return 0;
}
和open
之间差异的更多信息,您可以在此question的答案中找到。
<强>更新强>:
在检查PyPy代码库之后,我觉得doesn't use O_APPEND
flag出于某种原因,fopen
表示“a”模式。因此,正如J.F.Sebastian在another answer中提到的那样,在每次O_WRONLY | O_CREAT
调用之后,你需要seek
到文件末尾才是PyPy的真正原因。我想在PyPy bugtracker上应该创建一个bug,因为write
标志在Windows和Unix上都可用。那么,PyPy现在的表现如下:
O_APPEND
如果没有O_APPEND标志,它应该重现PyPy行为。
答案 1 :(得分:1)
O_APPEND
如果设置,则文件偏移量应设置为文件的末尾 在每次写作之前。
这意味着如果在“追加”模式下打开文件,则刷新其缓冲区时;内容应该到文件的末尾。
Python 2,Python 3,Jython尊重我的机器。在您的情况下,内容小于文件缓冲区,因此您可以看到来自一个文件的所有写入,然后是磁盘上结果中另一个文件的所有写入。
更容易理解文件是否是行缓冲的:
from __future__ import with_statement
filename = 'file1'
with open(filename, 'wb', 0) as file:
pass # truncate the file
f1 = open(filename, 'a', 1)
f2 = open(filename, 'a', 1)
f1.write('f1 1\n')
f2.write('f2 aa\n')
f1.write('f1 222\n')
f2.write('f2 bbbb\n')
f1.write('f1 333\n')
f2.write('f2 cc\n')
f1 1
f2 aa
f1 222
f2 bbbb
f1 333
f2 cc
Python文档并未强制要求此类行为。 It just mentions:
..'a'用于追加(在某些Unix系统上意味着所有写入追加到 该文件无论当前的搜索位置如何)强调是我的
Pypy在无缓冲和行缓冲模式下产生以下输出:
f2 aaff2 bbbf1f2 cc
手动将文件位置移动到末尾会修复pypy输出:
from __future__ import with_statement
import os
filename = 'file1'
with open(filename, 'wb', 0) as file:
pass # truncate the file
f1 = open(filename, 'a', 1)
f2 = open(filename, 'a', 1)
f1.write('f1 1\n')
f2.seek(0, os.SEEK_END)
f2.write('f2 aa\n')
f1.seek(0, os.SEEK_END)
f1.write('f1 222\n')
f2.seek(0, os.SEEK_END)
f2.write('f2 bbbb\n')
f1.seek(0, os.SEEK_END)
f1.write('f1 333\n')
f2.seek(0, os.SEEK_END)
f2.write('f2 cc\n')
如果文件是完全缓冲的,则在每个.flush()
之后添加.write()
。
同时使用多个文件对象写入同一文件可能不是一个好主意。