有趣的是,之前没有问过这样的问题。
我正在将数据行记录到Python2中的文本文件中。我想要做的是,通过行号,我想删除一行,但我不希望它被下一行填充,只留空(因此不必每次都写一个新文件)我划掉一条线。)
所以我问的不是其中之一,
基本概念是更改特定行的内容,在这种情况下,使用空字符串进行更改。
有一个问题,我没有真正理解,但可以包含我的问题的答案。如果是这样,请帮助我理解如何。
如果您认为我的问题与此问题重复,请在标记问题之前向我解释答案。
我对这个问题的研究:
file.seek()
( C喜欢功能有用吗?)编辑:我甚至忘记询问这样的事情是否可行,我将非常感谢您的信息。
答案 0 :(得分:3)
这是一个就地修改文本文件的函数,用相同长度的行替换指定的行。
在本演示中,我使用#
作为替换字符,以便更容易查看正在发生的事情。您可以使用简单空格(chr(32)
)或ASCII DEL字符(chr(127)
== \x7f
)。使用DEL的一个好处是它可以更快地删除所有这些“擦除”的行,因为该字符不会出现在任何文件的“正确”行中。
首先,这是一个用于测试此代码的小文本文件。
<强> Q数据强>
1 one
2 two
3 three
4 four
5 five
6 six
7 seven
8 eight
9 nine
这是代码。请注意,它使用从1开始的行号。
def erase_line(fname, line_num):
''' In-place replacement of line `line_num` in file `fname` with
a line of DEL chars of the same length, retaining the newline.
'''
DEL = '#'
with open(fname, 'r+') as f:
for i in range(line_num - 1):
f.readline()
start = f.tell()
line = f.readline()
line = DEL * (len(line) - 1) + '\n'
f.seek(start)
f.write(line)
erase_line('qdata', 3)
以下是 qdata 的修改版本:
1 one
2 two
#######
4 four
5 five
6 six
7 seven
8 eight
9 nine
因为它必须处理不同长度的行,erase_line
必须读取所有行,直到找到所需的行,但它只重写该行,它不会修改任何其他行,所以应该相当快。如果您的线条长度固定,我们可以使用.skip
立即跳转到所需的线条。
这是一个函数,它将删除任何完全由DEL字符组成的行,并将结果写入新文件。
def compact(oldname, newname):
''' Copy file `oldname` to `newname`, removing lines that
consist entirely of the DEL char, apart from the '\n'
'''
DEL = '#'
with open(oldname, 'r') as fin, open(newname, 'w') as fout:
for line in fin:
if not line.lstrip(DEL) == '\n':
fout.write(line)
compact('qdata', 'qdata.new')
<强> qdata.new 强>
1 one
2 two
4 four
5 five
6 six
7 seven
8 eight
9 nine
最后,这是一个执行压缩操作的Unix / Linux管道,假设您正在使用实际的DEL字符(八进制中为\177
)。它可能比我的Python版本更快。
tr -d '\177' <qdata | awk '!/^$/' >qdata.new
答案 1 :(得分:0)
这样的事情是你之后的事吗?
def remove_line_from_file(filename, line_number):
with open(filename) as f:
lines = f.readlines()
lines[line_number - 1] = '\n' # <- or whatever kind of newline is relevant for your system
with open(filename, 'w') as f:
f.writelines(lines)
然后,如果文件test
的内容是
line 1
line 2
line 3
正在运行remove_line_from_file('test', 2)
会将test
变为
line 1
line 3
更新,现在我确实正确地阅读了这个问题:这个方法修改了文件,用空白字符替换了行的内容:
def remove_line_from_file(filename, line_number):
with open(filename, 'r+') as f:
count = 0
bytes_read = 0
while True:
bytes_read += 1
this_byte = f.read(1)
if not this_byte:
break
if this_byte == '\n':
count += 1
if count == line_number - 1:
start = bytes_read
elif count == line_number:
f.seek(start)
f.write(' ' * (bytes_read - start - 1))
break
按照上述PM 2Ring的评论,使用chr(127)
代替' '
也是有意义的。
答案 2 :(得分:0)
你是对的,fileinput
module正是你所需要的:
import fileinput
def blank_line(filename, lineno):
f = fileinput.input(files=[filename], inplace=True)
for line in f:
if fileinput.lineno() == lineno: # note: line numbers start at 1, not 0
line = ""
print line.rstrip("\n") # Output is redirected to the current line of the file
f.close()
请注意,Python 3在这里有一些优势:fileinput
支持上下文管理器(with
语句),新的print()
函数允许我们完全保留行(而不是总是在最后添加换行符或空格。)
答案 3 :(得分:0)
您应该了解大多数系统上的文本文件文件是如何存储在磁盘或其他存储介质上的。
虽然不同系统之间的细节不同,但现在所有这些系统都具有固定大小的“块”的概念。
文件在这些块中分配,文本文件只是一系列字符,其中一些是0x0A
换行代码(*)。
比方说,例如一个块是32个字节(它们通常比那个大,但只是为了使图表更容易阅读)。
_______text file logical content________
|Hello, world¶ |
|This is a text file that contains¶ |
|three lines¶____________________________|
_______________________a 32 bytes block______________________
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
|H|e|l|l|o|,| |w|o|r|l|d|.|¶|T|h|i|s| |i|s| |a| |t|e|x|t| |f|i|
|l|e| |t|h|a|t| |c|o|n|t|a|i|n|s|¶|t|h|r|e|e| |l|i|n|e|s|¶|_|_|
如您所见,这三行占用了两个块,而第二个块的最后两个字节未使用。
文件系统将负责不显示那些额外的两个字节,但重点是文本文件的“行”无关 与磁盘上文件的结构:所有行都是一个接一个地连续写入,它们之间有特殊的换行符(**)。
例如,如果您想要用相同长度的另一行替换一行,则只需更新这几个字节即可。如果该行具有不同的长度,或者如果您想要删除或插入新行,唯一的解决方案是从该点实际重写整个文件到最后。
(*)小题外话:MS-DOS很久以前就用过,今后Windows使用两个字符
0x0D
+0x0A
来标记换行符,因为......好吧......没有人确切知道:这是一个愚蠢的愚蠢的愚蠢的不可原谅的甚至背后的选择,没有真正的理由,我们都必须永远活着。这个有两个换行符的错误是“二元模式”疯狂的基础。(**)第二个题外话:即使是今天非常“常见”的文件系统,其中文本文件具有固定长度的行而不是使用行终止字符,但它们仅用于存储银行帐户,保险单和其他COBOL程序不断改组的绝对重要信息,源代码很久以前就丢失了,而且无论如何都没有人保留任何严肃的存储库。如果这让你害怕,那就忽略它们,把所有的钱都留在床垫下。