使用Python在文件中间插入行吗?

问题描述 投票:48回答:8

有没有办法做到这一点?假设我有一个文件,其中包含这样的名称列表:

  1. 阿尔弗雷德
  2. 比尔
  3. 唐纳德

我如何在第x行(在本例中为3)中插入第三个名称“ Charlie”,并自动将所有其他名称发送到一行?我见过其他类似的问题,但是他们没有得到有用的答案。是否可以做到,最好使用方法或循环?

python
8个回答
67
投票

这是解决问题的方法。

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开始。


19
投票

如果要在文件中搜索子字符串并将新文本添加到下一行,执行此操作的一种简便方法如下:

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,

6
投票

您可以将数据读取到列表中并将新记录插入所需的位置。

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]))

5
投票

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

  1. 阿尔弗雷德
  2. 比尔
  3. 查理
  4. 唐纳德

(插入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()

5
投票

我发现有多种技术组合可以解决此问题:

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之后添加多个副本,因此可以安全地重复运行。


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

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)

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')         # Buffer will show up as a blank line

    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.

# Later, once you have the name to insert...
with open(filename, 'r+') as file:            # Must use 'r+' to write to middle of file 
    file.seek(insert_position)                # Move stream 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字符(或通常在文件中间的任何字符)。但是,空字符不会影响文件对人的外观(宽度为零)。


推荐问答