有办法做到这一点吗?假设我有一个文件列表,其名称如下:
如何在第x行(在本例中为3)插入第三个名称“Charlie”,并自动将所有其他名称下移一行?我见过这样的其他问题,但他们没有得到有用的答案。可以这样做,最好是用方法还是循环?
答案 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)
您没有向我们展示输出应该是什么样的,所以一种可能的解释是您希望将其作为输出:
(插入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)
file.readlines()
或file.read().split('\n')
list.insert()
在其中插入新的列表元素。答案 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字符(或通常在文件中间的任何位置)。但是空字符不会影响文件对人的外观(宽度为零)。