【问题标题】:Beginner Python: Reading and writing to the same file初学者 Python:读取和写入同一个文件
【发布时间】:2012-12-25 15:00:09
【问题描述】:

一周前开始使用 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。谢谢!

【问题讨论】:

    标签: python io


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      更新回复

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

      【讨论】:

      • 这很奇怪。如果我尝试这些行,似乎会出错: f=open("C:\Users\MooMoo\Desktop\clothes.txt","r+") print f.read() f.write("foooooooooooooo") .我收到的错误消息: Traceback(最近一次调用最后一次):文件“C:\Users\MooMoo\Desktop\Python27\PyProject\src\test.py”,第 43 行,在 f.write("foooooooooooooo" ) IOError: [Errno 0] 错误 f.close()
      • 这似乎是 Windows 特定的问题。我正在更新我的回复。要点:在写作之前使用 f.seek(f.tell())。
      【解决方案3】:

      每个打开的文件都有一个隐式指针,它指示数据将被读取和写入的位置。通常这默认为文件的开头,但如果您使用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的信息。

      【讨论】:

      • 嘿 Cartroo,不幸的是,我似乎确实理解了你的代码,但不知何故,当我编译时,它并没有给我你展示给我的东西。例如,我遵循了您在第一组示例中给出的确切代码集。当我检查文件时,文件中的文本只显示“这是一个测试文件”而不是“这是一个测试文件”。看起来写对我不起作用。如果有帮助,我正在使用 Python 2.7。
      • 从您的 cmets 看来,您使用的是 Windows - 正如我在回复中提到的,在同一文件中混合 read()write() 在 Windows 下似乎效果不佳,即使使用二进制模式-恐怕我对Windows还不够熟悉,无法说出原因。但是,seek() 似乎可以工作,所以在fd.write(" IS")之前添加这行fd.seek(4)。那个明确的seek() 似乎可以在 Windows 上运行。如果我能找到有关原始版本为何无法在 Windows 上运行的信息,我将在此处发表另一条评论。
      • 我对这种特定行为非常好奇,因此我提交了一个关于它的新问题:stackoverflow.com/questions/14279658/…
      • 实际上,如果你在第一次声明“fileOpen”对象后使用它来读取或写入,它不会更新任何内容。要写入同一个文件,我需要声明另一个“fileOpen”对象。我正在使用 Windows 7 并在 Eclipse 中使用 Python。我还在学习 Python,几乎所有的教程或书籍都说这不应该发生,所以我很困惑。
      【解决方案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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-29
        • 1970-01-01
        相关资源
        最近更新 更多