os.open/read/write/close 的可接受用法是什么?

5

我打算经常从许多不同的文件中读写小块信息。以下有点牵强附会的示例展示了使用os操作直接对文件描述符进行操作时所需时间大大减少。除了文件对象的便利性之外,我是否还错过了其他任何缺点?

import os
import time

N = 10000
PATH = "/tmp/foo.test"

def testOpen():
    for i in range(N):
        with open(PATH, "wb") as fh:
            fh.write("A")

    for i in range(N):
        with open(PATH, "rb") as fh:
            s = fh.read()

def testOsOpen():
    for i in range(N):
        fd = os.open(PATH, os.O_CREAT | os.O_WRONLY)
        try:
            os.write(fd, "A")
        finally:
            os.close(fd)

    for i in range(N):
        fd = os.open(PATH, os.O_RDONLY)
        try:
            s = os.read(fd, 1)
        finally:
            os.close(fd)

if __name__ == "__main__":
    for fn in testOpen, testOsOpen:
        start = time.time()
        fn()
        print fn.func_name, "took", time.time() - start

示例运行:

$ python bench.py 
testOpen took 1.82302999496
testOsOpen took 0.436559915543

Python的哪个版本? - user2682863
@user2682863,请注意,这必须是Python 2 - 在Python 3中,低级IO操作需要并返回“类似字节的对象”,而不是字符串。也就是说,这段代码在Py3下无法运行。 - Tim Peters
我正在使用2,但是我很好奇3是否有值得注意的区别。 - Ben
我更好奇的是2的哪个版本。我知道他们在最近的版本中对读写速度进行了很多改进。 - user2682863
1个回答

1

我回答一下,这样问题就不会一直悬而未决了 ;-)

其实可以说的不多:如你所注意到的,file 对象更为方便。在某些情况下,它也更加函数化;例如,它进行自己的缓存层来加速面向行的文本操作(如 file_object.readline()) (顺便说一下,这也是它较慢的原因之一)。并且 file 对象力求在所有平台上以相同的方式工作。

但如果您不需要/不想要那个,使用底层的、更快速的 os 文件描述符函数也没有任何问题。后者有许多函数,并且并非所有平台都支持所有函数,也并非所有选项都支持所有平台。当然,您需要自己负责将自己限制在您关心的平台的操作和选项的子集中(这通常适用于 os 中的所有函数,而不仅仅是它的文件描述符函数——os 的名称就是强烈的暗示,它所包含的东西可能是操作系统相关的)。

关于Python 2和3的区别,是由于Python 3在所有平台上都强烈区分“文本”和“二进制”模式。现在是Unicode时代,“文件”对象的“文本模式”如果没有指定预期编码就毫无意义。在Python 3中,如果以“文本模式”打开文件,则“文件”对象的读取方法返回一个“str”对象(Unicode字符串),否则返回一个“bytes”对象。写入方法也是同样的道理。
由于“os”文件描述符方法没有编码概念,在Python 3中它们只能使用类似字节的对象(无论是否在Windows上使用低级“os.open()”“O_BINARY”或“O_TEXT”标志打开文件描述符)。
实际上,在你给出的示例中,这意味着你需要更改以下内容:
"A"

b"A"

请注意,在Python 2的最新版本中,您也可以使用b"..."字面语法,尽管在Python 2中它仍然只是一个字符串字面量。在Python 3中,它表示一种不同类型的对象(bytes),文件描述符函数被限制为写入和返回类似于字节的对象。
但是,如果您正在处理“二进制数据”,那就没有任何限制。如果您正在处理“文本数据”,那么可能会有限制(关于您的具体情况没有足够的信息来猜测)。

谢谢,Tim。我很感激你这么长时间以来一直深度涉足Python的见解。我正在使用struct处理二进制数据。我只是想要一种简单的方式来尽可能快地存储和检索整数,而首要的file对象的性能惩罚似乎相当高,没有为我的用例提供任何好处。虽然我开始想如果我如此在意性能,那我应该使用C。 - Ben
更加重要的是速度,我就越坚持使用纯Python;-)说笑了一半:Python 可能非常慢,因此坚持使用 Python 迫使我想出根本性更好的方法。例如,也许您“真正”需要的是一个数据库,或者巧妙地使用字典等……表面上,仅为更改几个字节而打开和关闭文件并不可取:无论使用哪种语言,这都是高开销而工作量很少的操作。而且,随着你坚持使用Python时间越长,尝试其他方法就越容易 :-) - Tim Peters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接