繁体   English   中英

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

[英]How to insert text at line and column position in a file?

我想在文件中特定行的特定列插入一个字符串。

假设我有一个文件file.txt

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

我想改变最后一行,说How was the History test? 通过在第4行第13列添加字符串History

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

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

在一个大文件中,在更新需要发生的lineno之前不进行修改是有意义的。假设你有10K行的文件并且更新需要在9K发生,你的代码将不必要地加载内存中的所有9K行数据。 您拥有的代码仍然可以工作但不是最佳方式

你可以使用这段代码:

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)

readlines()函数读取整个文件。 但它没有必要。 它实际上从当前文件光标位置读取到结尾,在打开后恰好为0 (为了证实这一点,试试f.tell()后立即with语句)。如果我们开始什么更接近文件的结尾?

编写代码的方式意味着您对文件内容和布局的一些先验知识。 你能在每条线上设置任何限制吗? 例如,根据您的示例数据,我们可能会说保证行数为27个字节或更少。 让我们将其舍入到32为“2-ness的力量”并尝试从文件的末尾向后搜索

# 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个字节。 1 readlines() (在字节级)将查找行结束字节(在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字节),与磁盘或内存中的页面大小有关。

这个答案只会循环遍历文件一次,只会在插入后写入所有内容。 在插件位于末端的情况下,几乎没有开销,并且插件在开头处并不比完整的读写更糟糕。

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!

我不确定你是否在更改文件以包含单词“History”时遇到问题,或者你是否想知道如何只重写文件的某些部分,而不必重写整个文件。

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

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”)更改为空格等...当您向前移动文本时。

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

不幸的是,你的感受在这里误导了你。 文件的设计不容易修改。 简单地在文件中添加一行并不简单。

这看似简单的根源可能是你的文件的心理模型。 最有可能你使用的比喻是一张纸。 (在文件中将文件可视化为GUI中的文件),在纸上有足够的空白区域可以插入东西,只修改一行似乎很简单,你只需删除“测试?” 然后写“历史考试?” 额外的字符只是表示线条稍长一些,并且该线条上的空白区域较少。 没有其他线路需要触及,简单.....

不幸的是,一张纸与文本文件的真实情况完全不同。 一个文本文件本质上是一个很长的字符列表(位组),换行符只是另一个字符(通常由/n表示,所以它看起来更像是:

“英语测试怎么样?\\ n数学测试怎么样?\\ n化学测试怎么样?\\ n测试怎么样?\\ n编程测试怎么样?”

这就是大多数语言中的文本变量被称为字符串的原因。 文件中没有空间用于插入“历史记录以适应”的内容
插入后的字符不能滑动; 它们在磁盘上有固定位置,因此在插入后插入需要读取的每个字符,并将它们写入磁盘上的新位置。

这可以归结为,因为你必须扩展文件并在编辑后重写所有内容,因为它不值得做。 除非你处理可能不适合ram的大量文本文件。 它的方式更简单,效率也更低

  1. 将整个文件读入RAM
  2. 修改它
  3. 将整个文件写入磁盘。

这似乎效率低下,但这是计算机做得好的事情。 如果您想提高RAM效率,可以通过逐行读取将批量操作转换为流。

  1. 读取文件到内存的行,
  2. 修改线(或不)
  3. 将行写入新文件

查看实际代码的其他多个示例,我的答案目的是解决为什么将文本插入文件看起来像对文件的一个简单的小操作但实际上不是。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM