如果我无法从第一行迭代,如何从特定行开始读取文件

时间:2018-04-19 09:56:39

标签: python optimization

这是一个试图在最短的时间内到达线路并从那里开始的问题。

我有一个巨大的文本文件,我正在阅读并逐行执行操作。我目前正在跟踪我已解析的行号,以便在系统崩溃的情况下,我知道我做了多少。

如果我不想从头开始重新开始,如何重新开始阅读文件。

count = 0
all_parsed = os.listdir("urltextdir/")
with open(filename,"r") as readfile :
     for eachurl in readfile:
         if str(count)+".txt" not in all_parsed:
             urltext = getURLText(eachurl)
             with open("urltextdir/"+str(count)+".txt","w") as writefile:
                 writefile.write(urltext)
             result = processUrlText(urltext)
             saveinDB(result)

这就是我目前正在做的事情,但是当它崩溃了一百万行时,我不得不通过文件中的所有这些行来达到我想要开始的点,我的其他选择是使用readlines并将整个文件加载到内存中。

有没有我可以考虑的替代方案。

3 个答案:

答案 0 :(得分:1)

不幸的是,行号并不是文件对象的基本位置,而next会破坏特殊的搜索/告知功能,这在loop中会被调用。你不能跳到一行,但你可以到一个字节位置。所以一种方法是:

line = readfile.readline()
while line:
    line = readfile.readline(): #Must use `readline`!
    lastell = readfile.tell()
    print(lastell) #This is the location of the imaginary cursor in the file after reading the line 
    print(line) #Do with line what you would normally do
print(line) #Last line skipped by loop

现在您可以轻松地跳回

readfile.seek(lastell) #You need to keep the last lastell)

您需要将lastell保存到文件或打印,以便重新启动时知道您正在从哪个字节开始。

不幸的是,你不能使用书面文件,因为对字符数量的任何修改都会破坏基于此的计数。

这是一个完整的实现。创建一个名为tell的文件,并在其中放置0,然后您可以运行:

with open('tell','r+') as tfd:
    with open('abcdefg') as fd:
        fd.seek(int(tfd.readline()))         #Get last position
        line = fd.readline()                 #Init loop
        while line:
            print(line.strip(),fd.tell())    #Action on line
            tfd.seek(0)                      #Clear and
            tfd.write(str(fd.tell()))        #write new position only if successful
            line = fd.readline()             #Advance loop
        print(line)                          #Last line will be skipped by loop

您可以检查这样的文件是否存在,并在程序中创建它。

正如@Edwin在评论中指出的那样,你可能希望fd.flush()os.fsync(fd.fileno)import os,如果不清楚),以确保每次写入后你的文件内容都是实际上在磁盘上 - 这将适用于您正在执行的两个写操作,tell当然更快。这可能会让您大大减慢速度,因此如果您对同步性感到满意,请不要使用它,或只刷新tfd。您还可以在调用buffer大小时指定open,以便Python自动flushes更快,详见https://stackoverflow.com/a/3168436/6881240

答案 1 :(得分:0)

如果我做对了, 您可以创建一个简单的日志文件来存储计数。

但仍然会建议使用多个文件或将每个行或段存储在数据库le sql或mongoDB中

答案 2 :(得分:0)

我想这取决于您的脚本运行的系统,以及您可用的资源(如内存)。

但是流行的说法"内存很便宜",你可以简单地将文件读入内存。

作为测试,我创建了一个包含200万行的文件,每行包含1024个字符,代码如下:

ms = 'a' * 1024
with open('c:\\test\\2G.txt', 'w') as out:
    for _ in range(0, 2000000):
        out.write(ms+'\n')

这导致磁盘上有2 GB的文件。

然后我将文件读入内存中的列表,如下所示:

my_file_as_list = [a for a in open('c:\\test\\2G.txt', 'r').readlines()]

我检查了python进程,它在内存中使用了2 GB以上(在32 GB系统上) 访问数据的速度非常快,可以通过列表切片方法完成。

您需要跟踪列表的索引,当系统崩溃时,您可以再次从该索引开始。

但更重要的是......如果你的系统是"崩溃"然后你需要找出崩溃的原因......这几天肯定有几百万行数据不再是崩溃的原因......