初学者Python:读取和写入同一个文件

时间:2013-01-11 03:31:51

标签: python io

一周前开始使用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 个答案:

答案 0 :(得分:20)

更新回复

这似乎是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

答案 1 :(得分:7)

每个打开的文件都有一个隐式指针,指示数据的读写位置。通常,这默认为文件的开头,但如果使用a(追加)模式,则默认为文件末尾。同样值得注意的是,即使您将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.。这是因为初始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:\Users\johndoe\Desktop\testfile.txt", "r+")

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

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

您可以在official Python docs中找到有关文件IO的更多信息。

答案 2 :(得分:2)

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

答案 3 :(得分: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()