35

一周前开始使用 Python,我有一些关于读取和写入相同文件的问题要问。我已经在网上浏览了一些教程,但我仍然对此感到困惑。我可以理解简单的读写文件。

openFile = open("filepath", "r")
readFile = openFile.read()
print readFile 

openFile = open("filepath", "a")
appendFile = openFile.write("\nTest 123")

openFile.close()

但是,如果我尝试以下操作,我会在我正在写入的文本文件中得到一堆未知文本。谁能解释我为什么会遇到这样的错误以及为什么我不能按照下面显示的方式使用相同的 openFile 对象。

# 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()

我会尽力澄清我的问题。在上面的例子中,openFile是用来打开文件的对象。如果我想第一次写它,我没有问题。如果我想使用相同的openFile来读取文件或附加一些东西。它没有发生或给出错误。在对同一个文件执行另一个读/写操作之前,我必须声明相同/不同的打开文件对象。

#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()

如果有人能告诉我我在这里做错了什么,或者这只是 Pythong 的事情,我将不胜感激。我正在使用 Python 2.7。谢谢!

4

4 回答 4

28

更新的回应

这似乎是 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\nfasdfafasdfa\nsdfgsd\n'
>>> f.write("foooooooooooooo")
>>> f.close()
>>> f=open("a","r+")
>>> f.read()
'Test abc\nfasdfafasdfa\nsdfgsd\nfoooooooooooooo'

字符串“foooooooooooooo”被附加在文件末尾,因为指针已经在文件末尾。

您是否使用区分二进制文件和文本文件的系统?在这种情况下,您可能希望使用 'rb+' 作为模式。

在区分二进制文件和文本文件的系统上,将“b”附加到模式以二进制模式打开文件;在没有这种区别的系统上,添加“b”没有效果。 http://docs.python.org/2/library/functions.html#open

于 2013-01-11T03:49:10.100 回答
11

每个打开的文件都有一个隐式指针,指示数据将在何处被读取和写入。通常,这默认为文件的开头,但如果您使用a(append) 模式,则默认为文件的结尾。还值得注意的是,w即使您添加+到该模式,该模式也会截断您的文件(即删除所有内容)。

每当您读取或写入 N 个字符时,读/写指针将在文件中向前移动该数量。如果你还记得的话,我发现把它想象成一个旧的盒式磁带会有所帮助。因此,如果您执行以下代码:

fd = open("testfile.txt", "w+")
fd.write("This is a test file.\n")
fd.close()

fd = open("testfile.txt", "r+")
print fd.read(4)
fd.write(" IS")
fd.close()

...它应该最终打印This,然后将文件内容保留为This IS a test file.. 这是因为 initialread(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 系统,您可以测试这些示例来确定。但是,我在混合read()write()Windows 系统上遇到了问题。例如,当我在我的 Windows 机器上执行第一个示例时,它会正确打印This,但是当我之后检查文件时,它write()已被完全忽略。但是,第二个示例(使用seek())似乎在 Windows 上运行良好。

总之,如果您想在 Windows 中从文件的中间读取/写入,我建议始终使用显式seek()而不是依赖于读取/写入指针的位置。如果您只进行读取或仅写入,那么它非常安全。

最后一点 - 如果您在 Windows 上将路径指定为文字字符串,请记住转义反斜杠:

fd = open("C:\\Users\\johndoe\\Desktop\\testfile.txt", "r+")

r或者您可以通过在开头放置一个来使用原始字符串:

fd = open(r"C:\Users\johndoe\Desktop\testfile.txt", "r+")

或者最便携的选择是使用os.path.join()

fd = open(os.path.join("C:\\", "Users", "johndoe", "Desktop", "testfile.txt"), "r+")

您可以在Python 官方文档中找到有关文件 IO 的更多信息。

于 2013-01-11T10:25:04.760 回答
3

读取和写入发生在当前文件指针所在的位置,并且随着每次读取/写入而前进。在您的特定情况下,写入openFile, 会导致文件指针指向文件末尾。尝试从末尾读取会导致 EOF。seek(0)您需要重置文件指针,在读取文件之前指向文件的开头

于 2013-01-11T03:35:27.943 回答
0

您可以在 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()
于 2020-05-11T11:28:23.340 回答