用Python在文件中间插入行?

时间:2012-05-08 22:04:53

标签: python

有办法做到这一点吗?假设我有一个文件列表,其名称如下:

  1. 阿尔弗雷德
  2. 比尔
  3. 唐纳德
  4. 如何在第x行(在本例中为3)插入第三个名称“Charlie”,并自动将所有其他名称下移一行?我见过这样的其他问题,但他们没有得到有用的答案。可以这样做,最好是用方法还是循环?

10 个答案:

答案 0 :(得分:58)

这是一种做法的方法。

f = open("path_to_file", "r")
contents = f.readlines()
f.close()

contents.insert(index, value)

f = open("path_to_file", "w")
contents = "".join(contents)
f.write(contents)
f.close()

“index”和“value”是您选择的行和值,行从0开始。

答案 1 :(得分:16)

如果要搜索文件中的子字符串并将新文本添加到下一行,其中一种优雅的方法如下:

import fileinput
for line in fileinput.FileInput(file_path,inplace=1):
    if "TEXT_TO_SEARCH" in line:
        line=line.replace(line,line+"NEW_TEXT")
    print line,

答案 2 :(得分:5)

您只需将数据读入列表并将新记录插入所需的位置即可。

names = []
with open('names.txt', 'r+') as fd:
    for line in fd:
        names.append(line.split(' ')[-1].strip())

    names.insert(2, "Charlie") # element 2 will be 3. in your list
    fd.seek(0)
    fd.truncate()

    for i in xrange(len(names)):
        fd.write("%d. %s\n" %(i + 1, names[i]))

答案 3 :(得分:4)

您没有向我们展示输出应该是什么样的,所以一种可能的解释是您希望将其作为输出:

  1. 阿尔弗雷德
  2. 比尔
  3. 查理
  4. 唐纳德
  5. (插入Charlie,然后在所有后续行中添加1。)这是一个可能的解决方案:

    def insert_line(input_stream, pos, new_name, output_stream):
      inserted = False
      for line in input_stream:
        number, name = parse_line(line)
        if number == pos:
          print >> output_stream, format_line(number, new_name)
          inserted = True
        print >> output_stream, format_line(number if not inserted else (number + 1), name)
    
    def parse_line(line):
      number_str, name = line.strip().split()
      return (get_number(number_str), name)
    
    def get_number(number_str):
      return int(number_str.split('.')[0])
    
    def format_line(number, name):
      return add_dot(number) + ' ' + name
    
    def add_dot(number):
      return str(number) + '.'
    
    input_stream = open('input.txt', 'r')
    output_stream = open('output.txt', 'w')
    
    insert_line(input_stream, 3, 'Charlie', output_stream)
    
    input_stream.close()
    output_stream.close()
    

答案 4 :(得分:3)

  1. 使用file.readlines()file.read().split('\n')
  2. 将文件解析为python列表
  3. 根据您的标准确定您必须插入新行的位置。
  4. 使用list.insert()在其中插入新的列表元素。
  5. 将结果写入文件。

答案 5 :(得分:3)

我发现有一些技术可以解决这个问题:

with open(file, 'r+') as fd:
    contents = fd.readlines()
    contents.insert(index, new_string)  # new_string should end in a newline
    fd.seek(0)  # readlines consumes the iterator, so we need to start over
    fd.writelines(contents)  # No need to truncate as we are increasing filesize

在我们的特定应用程序中,我们希望在某个字符串之后添加它:

with open(file, 'r+') as fd:
    contents = fd.readlines()
    if match_string in contents[-1]:  # Handle last line to prevent IndexError
        contents.append(insert_string)
    else:
        for index, line in enumerate(contents):
            if match_string in line and insert_string not in contents[index + 1]:
                contents.insert(index + 1, insert_string)
                break
    fd.seek(0)
    fd.writelines(contents)

如果您希望它在匹配的每个实例之后插入字符串,而不仅仅是第一个,请删除else:(并且正确无效)和break

另请注意,and insert_string not in contents[index + 1]:会阻止它在match_string之后添加多个副本,因此可以安全地重复运行。

答案 6 :(得分:2)

已接受的答案必须将整个文件加载到内存中,这对于大文件而言效果不佳。以下解决方案将带有右行插入的新数据的文件内容写入同一目录(因此在同一文件系统上)的临时文件中,一次仅从源文件读取一小块。然后,它以efficient方式(Python 3.8+)用临时文件的内容覆盖源文件。

from pathlib import Path
from shutil import copyfile
from tempfile import NamedTemporaryFile

sourcefile = Path("/path/to/source").resolve()
insert_lineno = 152  # The line to insert the new data into.
insert_data = "..."  # Some string to insert.

with sourcefile.open(mode="r") as source:
    destination = NamedTemporaryFile(mode="w", dir=str(sourcefile.parent))
    lineno = 1

    while lineno < insert_lineno:
        destination.file.write(source.readline())
        lineno += 1

    # Insert the new data.
    destination.file.write(insert_data)

    # Write the rest in chunks.
    while True:
        data = source.read(1024)
        if not data:
            break
        destination.file.write(data)

# Finish writing data.
destination.flush()
# Overwrite the original file's contents with that of the temporary file.
# This uses a memory-optimised copy operation starting from Python 3.8.
copyfile(destination.name, str(sourcefile))
# Delete the temporary file.
destination.close()

编辑2020-09-08:我刚刚发现an answer on Code Review的功能与上述类似,但有更多解释-对某些人可能有用。

答案 7 :(得分:1)

location_of_line = 0
with open(filename, 'r') as file_you_want_to_read:
     #readlines in file and put in a list
     contents = file_you_want_to_read.readlines()

     #find location of what line you want to insert after
     for index, line in enumerate(contents):
            if line.startswith('whatever you are looking for')
                   location_of_line = index

#now you have a list of every line in that file
context.insert(location_of_line, "whatever you want to append to middle of file")
with open(filename, 'w') as file_to_write_to:
        file_to_write_to.writelines(contents)

这就是我最终得到想要插入到文件中间的任何数据的方式。

这只是伪代码,因为我很难对所发生的事情有清晰的了解。

基本上,您完全读取了文件并将其添加到列表中,然后将要插入的行插入该列表中,然后重新写入同一文件。

我确信有更好的方法可以做到这一点,虽然效率不高,但至少对我来说更有意义,我希望对其他人也有意义。

答案 8 :(得分:0)

一种简单但效率不高的方法是读取整个内容,对其进行更改,然后将其重写:

line_index = 3
lines = None
with open('file.txt', 'r') as file_handler:
    lines = file_handler.readlines()

lines.insert(line_index, 'Charlie')

with open('file.txt', 'w') as file_handler:
    file_handler.writelines(lines)

答案 9 :(得分:0)

对于特殊情况(您自己创建原始文件并碰巧知道插入位置),以下是一个稍显尴尬的解决方案(例如,您提前知道需要在名称前插入一行附加名称)。第三行,但直到您获取并写下其余名称后,才能知道名称。我认为,按照其他答案所述,读取,存储然后重新写入文件的全部内容,比使用此选项更为优雅,但是对于大文件而言可能是不可取的。

您可以在插入位置保留一个空字符('\ 0')缓冲区,以便以后覆盖:

num_names = 1_000_000    # Enough data to make storing in a list unideal
max_len = 20             # The maximum allowed length of the inserted line
line_to_insert = 2       # The third line is at index 2 (0-based indexing)

with open(filename, 'w+') as file:
    for i in range(line_to_insert):
        name = get_name(i)                    # Returns 'Alfred' for i = 0, etc.
        file.write(F'{i + 1}. {name}\n')

    insert_position = file.tell()             # Position to jump back to for insertion
    file.write('\0' * max_len + '\n')

    for i in range(line_to_insert, num_names):
        name = get_name(i)
        file.write(F'{i + 2}. {name}\n')      # Line numbering now bumped up by 1.

    file.seek(insert_position)                # Move stream back to the insertion line
    name = get_bonus_name()                   # This lucky winner jumps up to 3rd place
    new_line = F'{line_to_insert + 1}. {name}'
    file.write(new_line[:max_len])            # Slice so you don't overwrite next line

不幸的是,除非您重新编写随后的所有内容,否则无法删除任何没有被覆盖的多余null字符(或通常在文件中间的任何位置)。但是空字符不会影响文件对人的外观(宽度为零)。