【问题标题】:Read/Write text file读/写文本文件
【发布时间】:2013-05-12 08:57:00
【问题描述】:

我正在尝试更改文本文件中的某些行而不影响其他行。这就是名为“text.txt”的文本文件中的内容

this is  a test1|number1
this is a test2|number2
this is a test3|number2
this is a test4|number3
this is a test5|number3
this is a test6|number4
this is a test7|number5
this is a test8|number5
this is a test9|number5
this is a test10|number5

我的目标是更改第 4 行和第 5 行,但其余部分保持不变。

mylist1=[]
for lines in open('test','r'):
    a=lines.split('|')
    b=a[1].strip()
    if b== 'number3':
        mylist1.append('{}|{} \n'.format('this is replacement','number7'))
    else:
         mylist1.append('{}|{} \n'.format(a[0],a[1].strip()))
myfile=open('test','w')
myfile.writelines(mylist1)

即使代码有效,我想知道是否有更好更有效的方法来做到这一点?是否可以仅按行号读取文件?

【问题讨论】:

  • 不能在任意位置写入'a line',但如果想在读取时知道当前行号,可以使用enumerate,如for index, line in enumerate(open('test','r')):。如果您真的想通过编号而不是位置来识别行,这可能会有所帮助。顺便说一句:像你这样写'for lines'会产生误导——你每次通过循环得到的是一个single行。

标签: python io


【解决方案1】:

没有什么可以改进的。但是您必须将所有行写入一个新文件,无论是更改还是不变。较小的改进是:

  • 使用with 语句;
  • 避免在列表中存储行;
  • else 子句中写入lines 而不格式化(如果适用)。

应用以上所有:

import shutil
with open('test') as old, open('newtest', 'w') as new:
    for line in old:
        if line.rsplit('|', 1)[-1].strip() == 'number3':
            new.write('this is replacement|number7\n')
        else:
            new.write(line)
shutil.move('newtest', 'test')

【讨论】:

  • 你是对的。也许他可以使用内存文件(模块 StringIO)或临时文件(模块 tempfile),但基本上他不能对原始文件做任何事情。
  • 为什么当我将“newtest”更改为“test”时这不起作用?即使我必须重写以修改文件,我仍然需要它具有相同的名称。但非常感谢您的帮助
  • @ChrisAung 因为以写入模式打开文件会截断它。您会立即丢失旧内容。因此,您应该在完成后移动文件(请参阅我的编辑)或按照@jamylak 的建议使用fileinput;但如果您查看文档,fileinput 在内部也会这样做:创建一个备份文件,然后默默地删除它。
  • @LevLevitsky fileinput 使用 self._filename + (self._backup or os.extsep+"bak")) 你应该做类似的事情或使用 tempfile.NamedTemporaryFile 所以这是线程/进程安全的
【解决方案2】:
import fileinput

for lines in fileinput.input('test', inplace=True):
    # inplace=True redirects stdout to a temp file which will
    # be renamed to the original when we reach the end of the file. this
    # is more efficient because it doesn't save the whole file into memeory
    a = lines.split('|')
    b = a[1].strip()
    if b == 'number3':
        print '{}|{} '.format('this is replacement', 'number7')
    else:
        print '{}|{} '.format(a[0], a[1].strip())

【讨论】:

    【解决方案3】:

    没有。文件是面向字节的,不是面向行的,改变一行的长度不会推进后面的字节。

    【讨论】:

      【解决方案4】:

      试试这个解决方案

      with open('test', inplace=True) as text_file:
          for line in text_file:
               if line.rsplit('|', 1)[-1].strip() == 'number3':
                   print '{}|{} \n'.format('this is replacement', 'number7')
               else:
                   print line
      

      【讨论】:

        【解决方案5】:

        目前尚不清楚您的意图是用还是用它们的行号来确定要替换的行。

        如果前者是你的意图, 你可以得到这样的行列表:

        with open('test','r') as f:
            oldlines = f.read().splitlines()
        

        如果存在尾随空格的危险,您还可以:

        然后你可以像这样处理它们:

        newlines = [ line if not line.strip().endswith('|number3') else 'this is replacement|number7' for line in oldlines]
        

        打开目标文件(我假设你想覆盖原始文件,在这里),并写下所有行:

        with open('test','w') as f:
            f.write("\n".join(newlines))
        

        这是一种通用模式,可用于任何类型的简单行过滤。

        如果您打算通过数字来识别行,您可以只更改“换行符”行:

         newlines = [ line if i not in (3, 4) else 'this is replacement|number7' for i, line in enumerate(oldlines)]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-10
          • 2016-10-06
          • 2011-12-02
          • 1970-01-01
          • 1970-01-01
          • 2021-11-25
          • 1970-01-01
          • 2010-12-03
          相关资源
          最近更新 更多