提问人:Thomas the Programmer 提问时间:9/4/2023 更新时间:9/4/2023 访问量:21
尝试在前面添加或修改现有行会覆盖下一行的一部分
Trying to prepend or modify existing line is overwriting part of the next line
问:
我有一个主文件和一个临时文件。在这两个文件中,记录都遵循以下格式(冒号和 |'包括s)
Name:<name>|Field1:<int>|Field2:<str>|Field3:<str>|LockPID:<process id>
tmp 文件只有一条记录,主文件可以有一条或多条并发行记录
假设我想修改主文件中名为 Charles 的记录,我在“读取”模式下打开主文件,并使用以下函数查找带有 Charles 名称的行的字节号的内容:
def find_line_byte_position(file_name, target_line):
with open(file_name, "rb") as file:
current_byte_position = 0
for line in file:
if line.startswith(target_line.encode()):
return current_byte_position
# Increment the byte position by the length of the current line, including newline character(s)
current_byte_position += len(line)
# If the target line is not found, return -1 or raise an exception, as desired
return -1
假设我找到了字节位置,我现在可以查找该行
if recordExistsInMain:
main_file = open(main_filename, "r+")
main_file.seek(byteToSeek)
main_file.write(line)
如果我添加信息,我发现下一行的文本消失了。这是怎么回事?
这是一个示例,之前和之后(请注意,我出于这个问题的目的重命名了字段)
records.txt
Name:TAZ|Foo:100|Bar:
Name:CHRIS|Foo:200|Bar:
records.txt
Name:TAZ|Foo:100|Bar:yep
e:CHRIS|Foo:200|Bar:
我可以看到,通过在第 1 行添加 3 个字符,我在第 2 行丢失了 3 个字符。但是我没有丢失换行符,所以我对如何解决这个问题感到困惑。
我尝试使用 ljust 在主记录的第一行添加填充,然后对其进行修改,但文本仍然从第 2 行开始被吃掉。空格占用了字节,无论如何我都不想在它们上使用
替换 .txt 文件中的一行会损坏下一行和行本身 ^这看起来像同样的问题,但我不明白如何实现解决方案。其中唯一真正提供的是用空格填充(我猜我尝试过但未能实现)或读取和写入整个文件(我认为这有点傻?也许这就是解决方案)
注意:我想让它让多个人可以同时打开同一个脚本并修改同一个文件,我的想法是让它工作,如果每条记录被修改,只需向每条记录添加一个 lockPID - 只有具有相同 PID 的正确 Python 进程才能修改该记录。显然这是不安全的,但我只是为了学习而这样做
答:
如果我添加信息,我发现下一行的文本消失了。这是怎么回事?
这只是文件的行为:写入任何位置的文件流,但末尾将覆盖当前位于该位置的任何数据。
根据您的限制,以下是处理该问题的主要方法:
- 到目前为止,最简单和最常见的方法是创建一个新文件,而不是就地更新:将文件的开头复制到第二个文件,写入新位,复制文件末尾,然后复制到原始文件
rename()
- 如果内存比文件大小大得多,则只需将文件末尾(从插入点开始)插入内存,插入数据,然后重新插入文件内容
read()
- 如果你的内存有限,那么你必须做一些类似的事情,但从文件的末尾逐块:读取从 at 开始的块并将其写回 ,然后重复向后,直到你复制了插入点之后的任何内容
end() - buflen
end() - buflen + offset
第一个文件的缺点是您需要第二个文件,并且必须将大量数据从一个文件复制到另一个文件,但是在原子文件之前,不会触及任何重要内容。在其他两个版本中,如果操作过程中出现错误,则最终会得到一个损坏的文件。rename
注意:我想让它让多个人可以同时打开同一个脚本并修改同一个文件,我的想法是让它工作,如果每条记录被修改,只需向每条记录添加一个 lockPID - 只有具有相同 PID 的正确 Python 进程才能修改该记录。
这在时间上是非常糟糕的:两个进程可以打开()文件,检查 lockpid 字段,查看它是空的,然后同时写入它。然后,他们都会认为他们拥有对记录的独家访问权限,并且一切都被破坏了。
由于上述原因(你不能只写在文件的中间),这也根本不起作用,因为你的记录大小可变,所以写一条记录会影响其他记录的位置,这意味着对文件本身的并发访问是行不通的。
For this scheme to be even remotely workable you need fixed-size blocks into which variable-size records can be written (this way separate blocks can safely be accessed independently), and then you need some sort of concurrent access control to blocks, of which there really is none without an orchestrating process (POSIX advisory locks are generally considered not great at best and broken at worst).
In all honesty, if sqlite only allows one writer at a time it's for good reasons and I would suggest you do the same.
评论