前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 按行读取文本文件 缓存 和 非缓存实现

Python 按行读取文本文件 缓存 和 非缓存实现

原创
作者头像
代码伴一生
修改2021-11-02 11:28:03
1.5K0
修改2021-11-02 11:28:03
举报
文章被收录于专栏:代码伴一生代码伴一生

需求

最近项目中有个读取文件的需求,数据量还挺大,10万行的数量级。

java 使用缓存读取文件是,会相应的创建一个内部缓冲区数组在java虚拟机内存中,因此每次处理的就是这一整块内存。

简单的想:就是如果不用缓存,每次都要硬盘–虚拟机缓存–读取;有了缓存,提前读了一段放在虚拟机缓存里,可以避免频繁将硬盘上的数据读到缓存里。

因为对内存的操作肯定是比硬盘的操作要快的。

对了,java还有映射内存,可以解决大文件读写的问题。

思路

大文件读写不能一次全部读入内存,这样会导致耗尽内存。(但是在内存允许的情况下,全部读入内存是不是速度更快??) 对于大文件可以一行一行读取,因为我们处理完这行,就可以把它抛弃。

我们也可以一段一段读取大文件,实现一种缓存处理。每次读取一段文件,将这段文件放在缓存里,然后对这段处理。这会比一行一行快些。

方法1:一行一行读取

我们可以打开一个文件,然后用for循环读取每行,比如:

代码语言:javascript
复制
def method1(newName):
    s1 = time.clock()
    oldLine = '0'
    count = 0
    for line in open(newName):
        newLine =  line
        if (newLine != oldLine):
            #判断是不是空行
            if newLine.strip():
                nu = newLine.split()[0]
                oldLine = newLine
                count += 1
    print "deal %s lines" %(count)
    e1 = time.clock()
    print "cost time " + str(e1-s1)

我们测试一下

代码语言:javascript
复制
fileName = 'E:\\pythonProject\\ruisi\\correct_re.txt'
method1(fileName)

输出

代码语言:javascript
复制
deal 218376 lines
cost time 0.288900734402

方法1.1 一行一行读取的变形

代码语言:javascript
复制
def method11(newName):
    s1 = time.clock()
    oldLine = '0'
    count = 0
    file = open(newName)
    while 1:
        line = file.readline()
        if not line:
            break
        else:
            if line.strip():
                newLine =  line
                if (newLine != oldLine):
                    nu = newLine.split()[0]
                    oldLine = newLine
                    count += 1
    print "deal %s lines" %(count)
    e1 = time.clock()
    print "cost time " + str(e1-s1)
代码语言:javascript
复制
deal 218376 lines
cost time 0.371977884619

耗时和方法1差不多,比方法1稍微多些。

方法2:一行一行,使用fileinput模块

代码语言:javascript
复制
def method2(newName):
    s1 = time.clock()
    oldLine = '0'
    count = 0
    for line in fileinput.input(newName):
        newLine =  line
        if newLine.strip():
            if (newLine != oldLine):
                nu = newLine.split()[0]
                oldLine = newLine
                count += 1
    print "deal %s lines" %(count)
    e1 = time.clock()
    print "cost time " + str(e1-s1)
代码语言:javascript
复制
deal 218376 lines
cost time 0.514534051673

这儿的耗时差不多是方法1的两倍。

借助缓存,每次读取1000行

代码语言:javascript
复制
def method3(newName):
    s1 = time.clock()
    file = open(newName)
    oldLine = '0'
    count = 0
    while 1:
        lines = file.readlines(10*1024)
        #print len(lines)
        if not lines:
            break
        for line in lines:
            if line.strip():
                newLine =  line
                if (newLine != oldLine):
                    nu = newLine.split()[0]
                    oldLine = newLine
                    count += 1
    print "deal %s lines" %(count)
    e1 = time.clock()

Note readlinessizehint() 参数是限定字节大小,不是行数。 注意默认有个内部缓冲区大小是8KB,如果设定值小于 8*1024。那么都是按照8KB来的。print len(lines)输出大概都为290。 只有当设定值大于8KB,上面的print len(lines)才会发生变化。

代码语言:javascript
复制
deal 218376 lines
cost time 0.296652349397

这儿的性能还没方法1,表现好。可以调整每次读取的行数,比如500,1000等等,可以达到不同的耗时。

方法4 一次性全部读到内存里

代码语言:javascript
复制
def method4(newName):
    s1 = time.clock()
    file = open(newName)
    oldLine = '0'
    count = 0
    for line in file.readlines():
        if line.strip():
            newLine =  line
            if (newLine != oldLine):
                nu = newLine.split()[0]
                oldLine = newLine
                count += 1
    print "deal %s lines" %(count)
    e1 = time.clock()
    print "cost time " + str(e1-s1)

输出

代码语言:javascript
复制
deal 218376 lines
cost time 0.30108883108

结论

推荐使用

代码语言:javascript
复制
with open('foo.txt', 'r') as f:
    for line in f:
        # do_something(line)

对于大文件可以使用索引,这个索引记录下每行开头的位置,之后就可以用file.seek()定位了。如果文件内容修改了,还需要重新建立索引。这个索引可以有很多种方法建立,但是都需要将文件遍历一次。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求
  • 思路
  • 方法1:一行一行读取
  • 方法1.1 一行一行读取的变形
  • 方法2:一行一行,使用fileinput模块
  • 借助缓存,每次读取1000行
  • 方法4 一次性全部读到内存里
  • 结论
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档