如何在附加模式下寻找写指针?

How to seek write pointer in append mode?

我正在尝试打开一个文件来读取它的内容,然后使用之前读取的内容写入它。我正在以 'a+' 模式打开文件。我无法使用 'r+' 模式,因为如果文件不存在,它不会创建文件。

a+ 会将指针放在文件末尾。

可以用tell()保存,以后再写。

然后用seek(0,0)到return归档开始阅读。

tell()

seek()

默认开启

使用默认的 a(+) 选项,这是不可能的,如文档中所提供的:

''mode 是一个可选的字符串,指定文件所在的模式 被打开。它默认为 'r' 这意味着打开以阅读文本 模式。其他常用值是 'w' 用于写入(截断文件如果 它已经存在),'x' 用于创建和写入新文件, 和 'a' 用于追加(在某些 Unix 系统上,这意味着所有写入 无论当前搜索位置如何,都追加到文件末尾。''


备选

使用默认打开,这不是possible.However我们当然可以创建我们自己的文件处理程序,它将在rr+模式下创建一个文件,当它没有' t 存在。

一个与 open(filename, 'r+', *args, **kwargs) 完全相同的最小工作示例是:

import os


class FileHandler:
    def __init__(self, filename, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
        self.filename = filename
        self.mode = mode

        self.kwargs = dict(buffering=buffering, encoding=encoding, errors=errors, newline=newline, closefd=closefd)
        if self.kwargs['buffering'] is None:
            del self.kwargs['buffering']
    def __enter__(self):
        if self.mode.startswith('r') and not os.path.exists(self.filename):
            with open(self.filename, 'w'): pass
        self.file = open(self.filename, self.mode, **self.kwargs)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

现在当您使用以下代码时:

with FileHandler("new file.txt", "r+") as file:
    file.write("First line\n")
    file.write("Second line\n")
    file.seek(0, 0)
    file.write("Third line\n")

它将生成一个新文件 new file.txt,当它不存在时,上下文为:

Third line
Second line

如果您使用 open,如果文件不存在,您将收到 FileNotFoundError


备注

  • 我只在模式以 r 开始时创建一个新文件,所有其他文件都按正常 open 函数处理。
  • 出于某种原因,将 buffering=None 直接传递给 open 函数会使它崩溃并带有 TypeError: an integer is required (got type NoneType),因此我必须将其从关键字参数中删除,如果它是 None。尽管根据文档这是默认参数(如果有人知道为什么,请告诉我)

编辑

以上代码没有处理以下情况:

file = FileHandler("new file.txt", "r+")
file.seek(0, 0)
file.write("Welcome")
file.close()

为了支持 open 个用例中的 all 个,上面的 class 可以使用 __getattr__ 调整如下:

import os


class FileHandler:
    def __init__(self, filename, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
        self.filename = filename
        self.mode = mode

        self.kwargs = dict(buffering=buffering, encoding=encoding, errors=errors, newline=newline, closefd=closefd)
        if self.kwargs['buffering'] is None:
            del self.kwargs['buffering']

        if self.mode.startswith('r') and not os.path.exists(self.filename):
            with open(self.filename, 'w'): pass
        self.file = open(self.filename, self.mode, **self.kwargs)

    def __enter__(self):
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

    def __getattr__(self, item):
        if hasattr(self.file, item):
            return getattr(self.file, item)
        raise AttributeError(f"{type(self).__name__}, doesn't have the attribute {item!r}")