为什么读取和写入同一个文件会出现问题?
- 2025-02-25 09:07:00
- admin 原创
- 20
问题描述:
我有一些简单、有效的代码来读取和写入文件:
openFile = open("filepath", "r")
readFile = openFile.read()
print(readFile)
openFile = open("filepath", "a")
appendFile = openFile.write("
Test 123")
openFile.close()
但是,如果我尝试读取和写入同一个文件,我会收到错误,或者生成的文本不是我期望的。例如:
# I get an error when I use the codes below:
openFile = open("filepath", "r+")
writeFile = openFile.write("Test abc")
readFile = openFile.read()
print(readFile)
openFile.close()
为什么我不能这样写代码?如果我对open
同一个文件使用单独的调用,它似乎可以工作:
#I have no problems if I do this:
openFile = open("filepath", "r+")
writeFile = openFile.write("Test abc")
openFile2 = open("filepath", "r+")
readFile = openFile2.read()
print(readFile)
openFile.close()
解决方案 1:
更新后的回应:
这看起来像是 Windows 特有的一个错误 - http://bugs.python.org/issue1521491。
引用http://mail.python.org/pipermail/python-bugs-list/2005-August/029886.html中解释的解决方法
混合读取和写入对打开以进行更新的文件的影响是完全不确定的,除非在它们之间发生文件定位操作(例如 seek())。我无法猜测你期望发生什么,但似乎最有可能的是,你希望通过插入来可靠地获得你想要的东西
fp.seek(fp.tell())
在 read() 和 write() 之间。
我最初的回复演示了如何对打开的同一文件进行读取/写入以进行附加。如果您使用的是 Windows,这显然不是事实。
原始回应:
在 'r+' 模式下,使用 write 方法将根据指针的位置将字符串对象写入文件。 在本例中,它将字符串“Test abc”附加到文件的开头。 请参阅下面的示例:
>>> f=open("a","r+")
>>> f.read()
'Test abc
fasdfafasdfa
sdfgsd
'
>>> f.write("foooooooooooooo")
>>> f.close()
>>> f=open("a","r+")
>>> f.read()
'Test abc
fasdfafasdfa
sdfgsd
foooooooooooooo'
由于指针已经位于文件末尾,因此字符串“foooooooooooooo”被附加到文件末尾。
您的系统是否区分二进制文件和文本文件?在这种情况下,您可能希望使用“rb+”作为模式。
在区分二进制文件和文本文件的系统上,将“b”附加到模式以二进制模式打开文件;在没有这种区别的系统上,添加“b”不起作用。http
://docs.python.org/2/library/functions.html#open
解决方案 2:
每个打开的文件都有一个隐式指针,指示数据将在何处读取和写入。通常,默认为文件开头,但如果您使用a
(append) 模式,则默认为文件结尾。还值得注意的是,即使您向该模式添加内容,该w
模式也会截断文件(即删除所有内容) 。+
每当您读取或写入 N 个字符时,读/写指针都会在文件中向前移动该量。如果您还记得的话,我觉得把它想象成一盘旧磁带会有所帮助。因此,如果您执行以下代码:
fd = open("testfile.txt", "w+")
fd.write("This is a test file.
")
fd.close()
fd = open("testfile.txt", "r+")
print fd.read(4)
fd.write(" IS")
fd.close()
... 它应该最终打印This
并将文件内容保留为This IS a test file.
。这是因为初始read(4)
返回文件的前 4 个字符,因为指针位于文件的开头。它将指针留在紧接在 之后的空格字符处This
,因此以下将write(" IS")
用空格(与已经存在的相同)覆盖接下来的三个字符,然后是IS
,替换现有的is
。
你可以使用seek()
文件的方法跳转到特定点。在上述示例之后,如果你执行以下操作:
fd = open("testfile.txt", "r+")
fd.seek(10)
fd.write("TEST")
fd.close()
... 然后你会发现该文件现在包含This IS a TEST file.
。
所有这些都适用于 Unix 系统,您可以测试这些示例以确保无误。但是,我在 Windows 系统上混合使用read()
和时遇到了问题write()
。例如,当我在 Windows 机器上执行第一个示例时,它会正确打印This
,但当我随后检查文件时,它write()
被完全忽略了。但是,第二个示例(使用seek()
)似乎在 Windows 上运行良好。
总之,如果您想在 Windows 中从文件中间读取/写入,我建议始终使用显式,seek()
而不是依赖读/写指针的位置。如果您只执行读取或只执行写入,那么它非常安全。
最后一点 - 如果您在 Windows 上将路径指定为文字字符串,请记住转义反斜杠:
fd = open("C:\\Users\\johndoe\\Desktop\\testfile.txt", "r+")
r
或者你也可以通过在开头放置一个来使用原始字符串:
fd = open(r"C:UsersjohndoeDesktop estfile.txt", "r+")
或者最便携的选项是使用os.path.join()
:
fd = open(os.path.join("C:\\\", "Users", "johndoe", "Desktop", "testfile.txt"), "r+")
您可以在官方 Python 文档中找到有关文件 IO 的更多信息。
解决方案 3:
读取和写入发生在当前文件指针所在的位置,每次读取/写入时指针都会前进。在您的特定情况下,写入会导致文件指针指向文件末尾。尝试从末尾读取会导致 EOF。您需要重置文件指针,使其在读取之前openFile
指向文件的开头seek(0)
解决方案 4:
您可以在 python 中读取、修改和保存到同一个文件,但实际上您必须替换文件中的全部内容,并在更新文件内容之前调用:
# set the pointer to the beginning of the file in order to rewrite the content
edit_file.seek(0)
我需要一个函数来遍历文件夹的所有子目录并根据某些标准编辑文件的内容,如果它有帮助的话:
new_file_content = ""
for directories, subdirectories, files in os.walk(folder_path):
for file_name in files:
file_path = os.path.join(directories, file_name)
# open file for reading and writing
with io.open(file_path, "r+", encoding="utf-8") as edit_file:
for current_line in edit_file:
if condition in current_line:
# update current line
current_line = current_line.replace('john', 'jack')
new_file_content += current_line
# set the pointer to the beginning of the file in order to rewrite the content
edit_file.seek(0)
# delete actual file content
edit_file.truncate()
# rewrite updated file content
edit_file.write(new_file_content)
# empties new content in order to set for next iteration
new_file_content = ""
edit_file.close()