以下代码
fd = open(r"C:\folder1\file.acc", 'r')
fd.seek(12672)
print str(fd.read(1))
print "after", fd.tell()
正在返回after 16257
而不是预期的after 12673
这里发生了什么?有没有办法让文件的创建者可以对文件进行某种保护来搞乱我的读取?我只遇到一系列地址问题。文件的其余部分按预期读取。
答案 0 :(得分:3)
看起来好像是在尝试使用简单的"字节流处理文件,线性增加偏移量"模型,但是您使用'r'
而不是'rb'
打开它。鉴于路径名称以C:\
开头,我们还可以假设您在Windows系统上运行。 Windows上的 Text 流 - 无论是用Python打开,还是用各种其他语言打开,包括CPython的C基础 - 做有趣的翻译,其中Python中的'\n'
成为双字节序列{{1}在存储在文件中的字节内。这使得文件偏移以非线性方式运行(尽管作为避免使用Windows的人我不会想到精确的行为)。
因此,以'\r', '\n'
模式打开文件以进行阅读非常重要。当您使用Python3作为基本字符串使用Unicode时,这变得更加重要:打开模式为'rb'
的流生成 text ,如字符串'r'
,这是Unicode ;但是使用模式type 'str'
打开它会产生 bytes ,就像'rb'
的字符串一样。
如果您不想截断现有文件,可以使用<class 'bytes'>
进行写入,或r+b
创建新文件或截断任何现有文件。请记住,wb
表示&#34;添加其他模式&#34;,而+
表示&#34;截断现有或重新创建以便写入&#34;,因此w
被读取 - 而且没有截断的写入,而r+
是截断的写入和读取。在所有情况下,包括w+
表示&#34; ...并视为字节流。&#34;
正如你所看到的,这里有一个缺失的模式:你如何打开(仅)没有截断,但如果有必要创建文件?与C一样,Python为您提供了第三个字母选项b
(您也可以像往常一样与a
和+
混合使用)。这样就可以在没有截断的情况下进行写入,只在必要时创建一个新文件 - 但它有一些令人讨厌的副作用,即强制所有写入追加,这就是b
所代表的含义。这意味着您无法打开文件进行写入而不进行截断,将其置于中间位置,并仅覆盖其中一小部分。相反,您必须打开read-plus,位于其中间,并仅覆盖一位。但是读取加模式失败 - 如果文件当前不存在则引发a
异常。
您可以使用OSError
打开,如果失败,请使用r+
或w
重试,但此处的缺陷是操作非原子:如果两个或多个实体 - 让他们称之为Alice和Bob,虽然它们通常只是两个竞争程序 - 试图在单个文件名上执行此操作,但Alice可能会看到该文件还不存在,然后暂停一下;然后Bob看到该文件不存在,创建并截断它,写入内容并关闭它;然后Alice恢复,并创建并截断,丢失Bob的数据。 (实际上,像这样的两个竞争实体无论如何都需要合作,但为了可靠地进行,他们需要某种原子同步,为此你必须完成特定于操作系统的操作.Python 3.3添加了w+
个字符对于独占,这有助于实现原子性。)
如果你做打开一个阅读和写作的流,还有另一个恼人的警告:任何时候你希望&#34;切换方向&#34; you are required to introduce an apparently-pointless seek
。 (&#34;任何时候&#34;有点太强了:例如,在尝试读取产生文件结束之后,你也可以切换。然而,要记住的一组条件有点困难;在更改方向之前更容易说“#34;在#34;)这是继承自标准的C&#34;标准I / O&#34;实现。 Python 可以解决它 - 我现在正在搜索Python 3是否存在,并且没有找到答案 - 但Python 2没有。底层的C实现也不需要有这个缺陷,有些,比如我的,没有,但是最安全的假设它可能,并做明显无意义的搜索。