Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Python查找和替换大型文本文件中特定行的最快方法_Python_Performance_Optimization_Io_Full Text Search - Fatal编程技术网

用Python查找和替换大型文本文件中特定行的最快方法

用Python查找和替换大型文本文件中特定行的最快方法,python,performance,optimization,io,full-text-search,Python,Performance,Optimization,Io,Full Text Search,我有一个numbers.txt文件,它由几个100K行组成,每个行由两个用分隔的唯一数字组成:符号: 407597693:1604722326.2426915 510905857:1604722326.2696202 76792361:1604722331.120079 112854912:1604722333.4496727 470822611:1604722335.283259 我的目标是找到左侧编号为407597693的行,然后通过添加3600来更改右侧的编号。在那之后,我必须重写带有所

我有一个
numbers.txt
文件,它由几个100K行组成,每个行由两个用
分隔的唯一数字组成:
符号:

407597693:1604722326.2426915
510905857:1604722326.2696202
76792361:1604722331.120079
112854912:1604722333.4496727
470822611:1604722335.283259
我的目标是找到左侧编号为
407597693
的行,然后通过添加
3600
来更改右侧的编号。在那之后,我必须重写带有所有更改的
numbers.txt
文件。我必须尽可能快地对同一个txt文件执行相同的(只是不同的数字)操作

我已经通过打开:文件操作和每行的
for
循环,搜索所需的编号,修改行,然后重写整个文件,使其工作。但是,我注意到,持续执行这样的操作确实需要一些时间,大约0.2-0.5秒,这会随着时间的推移而增加,并大大降低速度

以下是我正在使用的代码:

number = 407597693

with open("numbers.txt", "r+") as library:
                file = library.read()
            if (str(number) + ":") in file:
                lines = file.splitlines()
                with open("numbers_temp.txt", "a+") as library_temp:
                    for line in lines:
                        if (str(number) + ":") in line:
                            library_temp.write(
                                "\n" + str(number) + ":" + str(time.time() + 3600)
                            )
                        else:
                            library_temp.write("\n" + line)

                    library_temp.seek(0)
                    new_file = library_temp.read()

                    with open("numbers.txt", "w+") as library_2:
                        library_2.write(new_file)

                os.remove("numbers_temp.txt")

我真的非常感谢任何关于如何加快这一进程的意见,非常感谢

我想你的内存可以存储整个文件。使用正则表达式应该更快:

import re
number = 407597693
with open("numbers.txt", "r") as f:
    data = f.read()
    # data = re.sub(f'({number}):(.*)', lambda x:f"{x.group(1)}:{float(x.group(2))+3600}", data)
    data = re.sub("^" + str(number) + ".*\n", str(number) + ":" + str(int(time.time()) + 3600) + "\n", data, flags=re.MULTILINE)
with open("numbers.txt", "w") as f:
    f.write(data)

与必须运行多个循环不同,我们可以在单个循环中执行此操作,如下所示:

number = 407597693
numbers = ''
with open('numbers.txt', "r+") as inputfile:
    file = inputfile.read()

    if(file.find(str(number))) != -1 :
        for line in file.splitlines():
            if (line.find(str(number))) == 0:
                numbers += line.split(':')[0] + ':' + str(float(line.split(':')[1]) + float(3600)) + '\n'
            else:
                numbers += line + '\n'

    with open('numbers.txt', 'w') as updatedFile:
    updatedFile.writelines(numbers)

希望这会有所帮助。

您可以打开一个内存映射文件,使用正则表达式查找所需的行,幸运的话,您只需更改文件中的一页即可。我使用的是十进制模块,这样就不会有十进制到二进制浮点的转换问题。通常,新编号和旧编号的宽度相同,不需要移动文件内容。我正在展示一个linux示例。Windows
mmap.map
有点不同,但应该易于使用

import mmap
import re
from decimal import Decimal

def increment_record(filename, findval, increment):
    with open(filename, "rb+") as fp:
        with mmap.mmap(fp.fileno(), 0) as fmap:
            search = re.search(rf"{findme}:([\d\.]+)".encode("ascii"), fmap, 
                    re.MULTILINE)
            if search:
                # found float to change. Use Decimal for base 10 precision
                newval = Decimal(search.group(1).decode("ascii")) + increment
                newval = f"{newval}".encode("ascii")
                delta = len(newval) - len(search.group(1))
                if delta:
                    # need to expand file and copy
                    fsize = fmap.size()
                    fmap.resize(fsize + delta)
                    fmap.move(search.end(1) + delta, search.end(1), 
                        fsize - search.end(1))
                # change just the number
                fmap[search.start(1):search.start(1) + len(newval)] = newval

# test parameters
filename = "test.txt"
findme = "76792361"
increment = 3600

testdata = """407597693:1604722326.2426915
510905857:1604722326.2696202
76792361:1604722331.120079
112854912:1604722333.4496727
470822611:1604722335.283259"""

open(filename, "w").write(testdata)

increment_record(filename, findme, increment)

print("changes:")
for old,new in zip(testdata.split("\n"), open(filename)):
    new = new.strip()
    if old != new:
        print((old,new))
print("done")

我怀疑这是一个错误。请备份并描述实际用例。我发现,依赖Python来维护文本文件、按需进行单行更新是站不住脚的。你能批量修改吗?你必须使用Python吗?为什么需要文本文件?这似乎更适合数据库应用程序。@Prune“您能批量更改吗?”-请澄清这个问题。“你必须使用Python吗?”-是的,因为这是我的复杂程序内置的语言。“为什么需要文本文件?”-由于用户必须能够直接轻松地访问信息+可以脱机查看+不需要任何其他软件来阅读和操作。这不是完整的答案,但我遇到了一个问题,我必须在250MB的文本文件中提取特定的操作,这些文件具有特定的边界点,指示新的记录结构。我得到了更快的响应,首先调用subprocess
grep
提前定位行,然后使用Python打开并搜索这些行,而不是在Python中扫描整个文件以查找这些边界点。文件中的许多内容在边界之间没有任何意义。您的回答部分正确。虽然使用regex将完成任务所需的时间减少了4倍,但您的特定代码对我来说并不太合适。我必须更改的部分是:
data=re.sub(“^”+str(number)+“*\n”,str(number)+:“+str(int(time.time())+3600)+“\n”,data,flags=re.MULTILINE)
。我会将你的答案标记为解决方案,但也许你会想将你的代码行更改为我的代码行,因为我已经测试过了,而且看起来更简单。哦,是的,我把
f
放在字符串中,应该在开头。