当前位置 : 首页 » 博文聚焦 » 正文

python操作大文件

分类 : 博文聚焦 | 发布时间 : 2018-03-16 11:53:56 | 浏览 : 78

        环境python3.6+win10

    python已经有很多现成的模块(如pandas)打开文件,我们能很轻易的根据编码打开文件得到我们需要的内容。但是有几个坑需要知道:1.不知道文件的编码如何打开文件;2.文件太大而只需要打开一部分如何快速打开文件;

    打开文件是大家都知道的。而一般推荐使用codecs.open用指定的编码打开文件。这样可以编码文件在打开写入的时候出现错误。这里我先介绍一下基础的操作文件模式:


w     以写方式打开,

a     以追加模式打开 (从 EOF 开始, 必要时创建新文件)

r+     以读写模式打开

w+     以读写模式打开 (参见 w )

a+     以读写模式打开 (参见 a )

rb     以二进制读模式打开

wb     以二进制写模式打开 (参见 w )

ab     以二进制追加模式打开 (参见 a )

rb+    以二进制读写模式打开 (参见 r+ )

wb+    以二进制读写模式打开 (参见 w+ )

ab+    以二进制读写模式打开 (参见 a+ )


打开文件需要注意的是是否报错和时候覆盖原来文件的问题。

复制代码
模式 可做操作 若文件不存在 是否覆盖
r 只能读 报错 -
r+ 可读可写 报错
w 只能写 创建
w+ 可读可写 创建
a 只能写 创建 否,追加写
a+ 可读可写 创建 否,追加写

read([size])方法从文件当前位置起读取size个字节,若无参数size,则表示读取至文件结束为止,它范围为字符串对象

readline()从字面意思可以看出,该方法每次读出一行内容,所以,读取时占用内存小,比较适合大文件,该方法返回一个字符串对象。

readlines()方法读取整个文件所有行,保存在一个列表(list)变量中,每行作为一个元素,但读取大文件会比较占内存。

下面我们来看看打开文件的实例:
# 判断文本文件的编码,输出指定行并计算程序运行时间
import datetime
import time
import os
import chardet
import codecs

 def timeit(func):    # 计算程序运行时间的函数
    def wrapper():
        starttime=datetime.datetime.now()
        func()
        endingtime=datetime.datetime.now()
        cost=(endingtime-starttime).seconds
        print ('程序总共用了'+str(cost)+'秒钟')
    return wrapper

@timeit  # 使用装饰器
def test():
    with codecs.open('d:\\school\\card_final_test.txt','rb') as fb:
        text_coding=chardet.detect(fb.readline())   # 获取文件的编码信息,得到字典类型数据
        t_coding=text_coding.get('encoding')     # 获取文件编码格式
        print (t_coding)
    with codecs.open('d:\\school\\card_final_test.txt','r+',encoding=t_coding) as fb:
        for i,j in enumerate(fb):  
            if 0<i<80000:    # 获取0-80000行的数据
                print (j.strip())
            elif i>80000:
                break

    python文件已经可以正确打开了。但是如何读取文件?如果文件很大甚至超过内存,一次性将文件全部读入到内存很可能会提示错误,所以read()和readlines()这两种方式只适合于打开比较小的文件(相对于内存来说)。而对于大文件有以下几种处理方式:

1.利用open(“”, “”)系统自带方法生成的迭代对象

    for line in f 这种用法是把文件对象f当作迭代对象, 系统将自动处理IO缓冲和内存管理, 这种方法是更加pythonic的方法。 比较简洁。 其实上例已经用到了,比较方便。

import datetime
import time
import os
import chardet
import codecs

def timeit(func):
    def wrapper():
        starttime=datetime.datetime.now()
        func()
        endingtime=datetime.datetime.now()
        cost=(endingtime-starttime).seconds
        print ('程序总共用了'+str(cost)+'秒钟')
    return wrapper

@timeit
def test():
    with codecs.open('d:\\school\\card_final_test.txt','rb') as fb:
        text_coding=chardet.detect(fb.readline())
        t_coding=text_coding.get('encoding')
        print (t_coding)
    with codecs.open('d:\\school\\card_final_test.txt','r+',encoding=t_coding) as fb:
            for i in fb:
                print (i.strip())

2.将文件切分成小段,每次处理完小段内容后,释放内存

这里会使用yield生成自定义可迭代对象, 即generator, 每一个带有yield的函数就是一个generator。

根据相同的数据量比对。使用文件块读取的文件比较快一点。


import datetime
import time
import os
import chardet
import codecs

def timeit(func):
    def wrapper():
        starttime=datetime.datetime.now()
        func()
        endingtime=datetime.datetime.now()
        cost=(endingtime-starttime).seconds
        print ('程序总共用了'+str(cost)+'秒钟')
    return wrapper

def read_in_block(file_path):
    BLOCK_SIZE = 1024*1024  # 指定读取每块1024字节
    with codecs.open(file_path, "r",encoding='utf-8') as f:
        while True:
            block = f.read(BLOCK_SIZE)  # 每次读取固定长度到内存缓冲区
            if block:
                yield block
            else:
                return  # 如果读取到文件末尾,则退出

@timeit
def test3():
    file_path = r'd:\\school\\card_final_test.txt'
    for block in read_in_block(file_path):
        print (block)

    经过比较,使用分块读取文件的速度要快很多。可见python的内存管理并没有想象的那么好。下面要说文件操作的用法。python对文件的操作非常灵活:

范例1:

with open('d:\\ww.txt','r') as f1,open('d:\\new.txt','w') as f2:
    a=f1.readlines()
    for i,j in enumerate(a):
        if 20<i<30:
            f2.write(j)

范例2:

语法格式:file.seek(offset, whence=0)

    offset: 偏移量,需要向前或者是向后移动的字节

    whence: 可选值,默认为0, 可选值为1或者2,表示从何处开始计算偏移,具体来说,

--> 0表示从当前位置开始计算偏移
--> 1表示从文件头位置开始计算偏移
--> 2表示从文件尾开始计算偏移

with codecs.open('d:\\test\\b.txt','r',encoding='gbk') as f:
    print(len(f.readline()))
    f.seek(2,1)
    print (f.tell())  #获取当前文件读取指针的位置
    print (f.read())
    print (f.read())

    print ('$'*20)
    f.seek(0,0) # 从文件头开始
    f.seek(14,1)  #每行结尾都有一个‘\n’
    print (f.tell())
    print (f.read(4))
    print ('$'*20)
    cd=f.seek(2,2)
    print (f.tell())
    print (f.readline())
    print ('$'*20)
    f.seek(-2,2)
    print (f.readline())

    仓促写就,定有不足之处。希望大家能予以斧正!多谢!rwangnqian@126.com






相关阅读:

python操作大文件

由浅入深了解python里面的函数,闭包,装饰器

关于编码问题的理解(python)

python数据类型

python中的os函数

python中的map函数

python 列表数据的保存

python中的list函数(部分截取)

python中的yeild

python基础---理解面向对象