如何在文件中的行和列位置插入文本?



我想在文件中特定行的特定列处插入一个字符串,而无需读取和重写整个文件。

假设我有一个文件file.txt

How was the English test?
How was the Math test?
How was the Chemistry test?
How was the test?

我想通过在第 4 行第 13 列添加字符串History来更改最后一行以表示How was the History test?

目前,我读取文件的每一行并将字符串添加到指定位置。

with open("file.txt", "r+") as f:
# Read entire file
lines = f.readlines()
# Update line
lino = 4 - 1
colno = 13 -1
lines[lino] = lines[lino][:colno] + "History " + lines[lino][colno:]
# Rewrite file
f.seek(0)
for line in lines:
f.write(line)
f.truncate()
f.close()

但我觉得我应该能够简单地将行添加到文件中,而无需读取和重写整个文件。

这可能是下面SO线程的副本

在 Python 中从大文件中删除一行的最快方法

在上面是关于删除的讨论,这只是一种操纵,而你的更多的是一种修改。所以代码会像下面这样更新

def update(filename, lineno, column, text):
fro = open(filename, "rb")
current_line = 0
while current_line < lineno - 1:
fro.readline()
current_line += 1
seekpoint = fro.tell()
frw = open(filename, "r+b")
frw.seek(seekpoint, 0)
# read the line we want to update
line = fro.readline()
chars = line[0: column-1] + text + line[column-1:]
while chars:
frw.writelines(chars)
chars = fro.readline()
fro.close()
frw.truncate()
frw.close()

if __name__ == "__main__":
update("file.txt", 4, 13, "History ")

在一个大文件中,直到需要更新的行号之前不进行修改是有意义的,想象一下你有 10K 行的文件,更新需要在 9K 进行,你的代码将不必要地加载内存中的所有9K行数据。您拥有的代码仍然可以工作,但不是最佳方法

函数readlines()读取整个文件。 但并非必须如此。 它实际上从当前文件光标位置读取到末尾,这恰好在打开后立即0。 (要确认这一点,请在with语句后立即尝试f.tell()。 如果我们从接近文件末尾开始怎么办?

编写代码的方式意味着对文件内容和布局有一些先验知识。 你能对每行施加任何约束吗? 例如,给定您的示例数据,我们可能会说行保证为 27 字节或更少。 让我们将其四舍五入为 32 以获得"2 的幂",并尝试从文件末尾向查找。

# note the "rb+"; need to open in binary mode, else seeking is strictly
# a "forward from 0" operation.  We need to be able to seek backwards
with open("file.txt", "rb+") as f:
# caveat: if file is less than 32 bytes, this will throw
# an exception.  The second parameter, 2, says "from end of file"
f.seek(-32, 2)
last = f.readlines()[-1].decode()

此时,代码仅读取文件的最后 32 个字节。1readlines()(在字节级别)将查找行结束字节(在 Unix、n0x0a或字节值 10 中),并返回前后。 阐明:

>>> last = f.readlines()
>>> print( last )
[b'hemistry test?n', b'How was the test?']
>>> last = last[-1]
>>> print( last )
b'How was the test?'

至关重要的是,这在 UTF-8 编码下非常有效,因为它利用了UTF-8 属性,即在编码非 ASCII 字节时不会出现低于 128 的 ASCII字节值。 换句话说,确切的字节n(或0x0a)只作为换行符出现,而不是作为字符的一部分出现。 如果您使用的是非 UTF-8 编码,则需要检查代码假设是否仍然成立。

另一个注意事项:给定示例数据,32 字节是任意的。 更实际和典型的值可能是 512、1024 或 4096。 最后,把它放回一个工作示例:

with open("file.txt", "rb+") as f:
# caveat: if file is less than 32 bytes, this will throw
# an exception.  The second parameter, 2, says "from end of file"
f.seek(-32, 2)
# does *not* read while file, unless file is exactly 32 bytes.
last = f.readlines()[-1]
last_decoded = last.decode()
# Update line
colno = 13 -1
last_decoded = last_decoded[:colno] + "History " + last_decoded[colno:]
last_line_bytes = len( last )
f.seek(-last_line_bytes, 2)
f.write( last_decoded.encode() )
f.truncate()

请注意,不需要f.close()with语句会自动处理该语句。

1迂腐的人会正确地注意到,计算机和操作系统可能至少读取了 512 个字节,如果不是 4096 个字节,则与磁盘或内存中的页面大小有关。

您可以使用这段代码:

with open("test.txt",'r+') as f:
# Read the file 
lines=f.readlines()
# Gets the column
column=int(input("Column:"))-1
# Gets the line
line=int(input("Line:"))-1
# Gets the word
word=input("Word:")
lines[line]=lines[line][0:column]+word+lines[line][column:]
# Delete the file
f.seek(0)
for i in lines:
# Append the lines
f.write(i)

这个答案只会循环访问文件一次,并且只在插入后写入所有内容。在插入位于末尾的情况下,几乎没有开销,并且在开头插入时,它并不比完全读写差。

def insert(file, line, column, text):
ln, cn = line - 1, column - 1         # offset from human index to Python index
count = 0                             # initial count of characters
with open(file, 'r+') as f:           # open file for reading an writing
for idx, line in enumerate(f):    # for all line in the file
if idx < ln:                  # before the given line
count += len(line)        # read and count characters 
elif idx == ln:               # once at the line                                 
f.seek(count + cn)        # place cursor at the correct character location
remainder = f.read()      # store all character afterwards                       
f.seek(count + cn)        # move cursor back to the correct character location
f.write(text + remainder) # insert text and rewrite the remainder
return                    # You're finished!

我不确定您是否在更改文件以包含"历史记录"一词时遇到问题,或者您是否想知道如何只重写文件的某些部分,而不必重写整个内容。

如果您遇到一般问题,这里有一些简单的代码应该可以工作,只要您知道文件中要更改的行。只需更改程序的第一行和最后一行即可相应地读取和写入语句。

fileData="""How was the English test?
How was the Math test?
How was the Chemistry test?
How was the test?""" # So that I don't have to create the file, I'm writing the text directly into a variable.
fileData=fileData.split("n")
fileData[3]=fileData[3][:11]+" History"+fileData[3][11:] # The 3 referes to the line to add "History" to. (The first line is line 0)
storeData=""
for i in fileData:storeData+=i+"n"
storeData=storeData[:-1]
print(storeData) # You can change this to a write command.

如果您想知道如何在不重写整个文件的情况下将特定"部分"更改为文件,那么(据我所知)这是不可能的。

假设你有一个文件,上面写着Ths is a TEST file.,你想把它更正成This is a TEST file.;从技术上讲,你会改变17个字符,并在末尾添加一个。您要将"s"更改为"i",将第一个空格更改为"s","i"(从"is")更改为空格,等等...当您向前移动文本时。

计算机实际上不能在其他字节之间插入字节。它只能移动数据,以腾出空间。

最新更新