PyPy文件附加模式

时间:2014-04-18 14:24:53

标签: python pypy

我有这样的代码:

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中不存在这个问题。

2 个答案:

答案 0 :(得分:3)

不同行为的原因是文件I / O操作的不同实现。

CPython implements它是来自fopen的{​​{1}},freadfwrite函数之上的文件I / O,正在使用stdio.h流。

同时PyPy implements它是在POSIX FILE *openwrite函数之上的文件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)

On POSIX systems

  

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()

同时使用多个文件对象写入同一文件可能不是一个好主意。