以'r'和'w'模式同时打开同一文件致内容丢失问题排查
问题分析与修复:文件被清空的原因及解决办法
原代码
def repair(): option_dict = {'1': 'Save', '2': 'Save_as', '3': 'run'} i = 1 options_read = open('keybinds.options', 'r') options_write = open('keybinds.options', 'w', encoding='utf-8') for line in options_read.readlines(): line = line.strip() if line.startswith(f'{option_dict[str(i)]}:'): i += 1 else: print(f'Repairing keybind #{i} ({option_dict[str(i)]})') lines = options_read.readlines() lines[i-1] = option_dict[str(i)] + ": " + "\n" options_write.write(lines) i += 1 repair()
原文件内容
Save: <Control-s> Save_as: <Control-o> run: <Control-r>
问题原因
- 同时读写触发文件清空:用
w模式打开文件时,操作系统会直接清空文件内容,此时读操作还未完成,文件已经是空的了。 - 文件指针到末尾导致空读:第一次调用
options_read.readlines()已经读取完所有内容,文件指针移到末尾,后续再调用readlines()只会返回空列表。 write()不支持直接写入列表:file.write()仅接受字符串参数,直接传列表会报错,导致逻辑无法正常执行。
修复后的代码
def repair(): option_dict = {'1': 'Save', '2': 'Save_as', '3': 'run'} i = 1 # 一次性读取所有内容到内存,自动关闭文件 with open('keybinds.options', 'r', encoding='utf-8') as f: lines = f.readlines() # 遍历处理每一行 for idx in range(len(lines)): line = lines[idx].strip() if line.startswith(f'{option_dict[str(i)]}:'): i += 1 else: print(f'Repairing keybind #{i} ({option_dict[str(i)]})') lines[idx] = f'{option_dict[str(i)]}:\n' i += 1 # 写入处理后的内容 with open('keybinds.options', 'w', encoding='utf-8') as f: f.writelines(lines) repair()
修复说明
- 用
with语句自动管理文件句柄,避免资源泄漏。 - 先读取全部内容到内存再处理,规避文件指针偏移问题。
- 使用
writelines()直接写入列表,或拼接成字符串后用write()写入,适配文件操作要求。 - 通过索引遍历列表,确保每一行都能被正确校验和修改。
内容的提问来源于stack exchange,提问作者RGB_CATT
相关产品推荐
相关产品推荐

