从一个字节流中进行按行读取

简介: 从一个字节流中进行按行读取

今天看到了一段代码,值得记录下来。这种写法一般会写在C语言里面做文件读写,很少会用到python之中。对于一个文件而言,如果是一个文本文件,按行读取可以直接使用python自带的方法,一般会用下面这种写法

with open(file_path, 'r') as fp:
    for line in fp:
        print(line)

在python里面可以直接对一个文件对象进行迭代,迭代的每一个结果都是文件中的每一行,这里分行是python本身来做的处理。如果是使用二进制模式打开,该怎么以流的形式读取一个文件中的每一行?

下面是一种非常优雅的写法:

# 一个使用字节模式打开的文件
fp = open(file_path, 'rb') 
def read_by_line(fp):
    # 每次读取的大小 1024字节
    BLOCK_SIZE = 1024
    # 保存最后一个换行符后面的内容
    # 原因:因为只读取了BLOCK_SIZE个大小
    # 最后一个换行符后面的内容的情况是未知的
    # 在比特流的视角下
    # xxxxxx \n xxxxxxx \n x xxxxxxxx
    # ---------------------* ————————
    #        第一次读取     
    # 每一次读取都应该将*号处(即最后一个换行符后面的数据)的数据和下次读取的数据合并起来
    # 这里 会有两种情况:
    # 1. 本次读取已经读完了所有数据
    # 2. 本次没有读取完,还有下次读取
    last_line = ''
    while True:
        data = fp.read(BLOCK_SIZE)
        # 每次读取的数据中有两种情况
        # 第一种:data种包含换行符\n,可能包含一个也可能包含多个
        # 第二种:data种不包含换行符\n
        if not data:
            # 所有数据都读取完了以后,中断循环
            break
        # 每次读取都和上一次读取的数据中最后一个换行符\n后面的数据连接起来
        data = "".join((last_line, data.decode()))
        # 将合并起来的数据再按照\n进行分割
        lines = data.split('\n')
        # 将每次读取的数据最后一个换行符后面的数据都保存起来
        # 以便于和下次的数据合并起来
        last_line = lines.pop()
        # 最后一个换行符之前的数据是没有争议的
        # 这里直接将他通过生成器返回出去
        # 当然这里还会有两种情况
        # 1. lines是一个空list, 因为前面的数据一直没有读取到换行符
        #    所以每次的数据都被保留起来,和下次的数据合并起来
        # 2. lines里面是有内容的,说明data中不止一个换行符\n
        #    这里可以将前几个换行符分割产生的行返回出去
        #    因为他们绝对不会和后面的数据有联系
        for line in lines:
            yield line
    # 所有的数据都读取完了,将最后一个换行符后的结果返回出去
    yield last_line

当然,这里如果是一个可以用文本模式直接打开的文件,最好还是使用第一种方法,第二种方法的优点在于,可以直接从一个字节流中按行进行返回。

一个很有用的场景就是,将一个文本文件使用gzip压缩以后,在不解压的前提下,可以直接在压缩的字节流上直接进行按行读取。下面是一个很有用的例子,相对于上面的代码,只需要改动很小的一部分:

# 将fp文件跟改成gzip的open
+ import gzip
+ fp = gzip.open(file_path)
+ def decompress(chunk):
+     # 解压函数
+     pass
def read_by_line(fp):
    BLOCK_SIZE = 1024
    last_line = ''
    while True:
        data = fp.read(BLOCK_SIZE)
        if not data:
            break
        # 在这里
-       data = "".join((last_line, data.decode()))
+       data = "".join(last_line, decompress(data))    #需要对读取的数据做解压
        lines = data.split('\n')
        last_line = lines.pop()
        for line in lines:
            yield line
    yield last_line
相关文章
|
存储 移动开发 Java
JavaNIO实现按行读取文件操作
在Java编程中,文件操作常常是必不可少的步骤。在对文件进行操作时,按行读取文件是一个常见需求。Java提供了多种方法实现按行读取文件,其中一种方法是使用JavaNIO。
219 0
字符流读取写入文件
字符流读取写入文件
129 0
将数据从文件中读出并排序
将数据从文件中读出并排序
158 0
|
C++
c++ 字符输入读取
cin.clear()重置输入流 cin.get()锁住屏幕直到获取输入 while(cin) cin.get(ch) 方法返回的是一个cin对象,istream类提供了可以将istream对象转换为bool 当cin出现在需要bool地方,eg:while的测试条件中,将cin对象转换为bool的...
1127 0
|
3月前
从文件中读取一行
从文件中读取一行。
37 5
C++读取单个字符操作
get() 是 istream 类的成员函数,它有多种重载形式,不过本文只介绍最简单最常用的一种: int get(); 此函数从输入流中读入一个字符,返回值就是该字符的 ASCII 码。 如果碰到输入的末尾,则返回值为 EOF。EOF 是 End of File 的缩写。istream 类中从输入流(包括文件)中读取数据的成员函数,在把输入数据都读取完后再进行读取,就会返回 EOF。 EOF 是在 iostream 类中定义的一个整型常量,值为 -1。get() 函数不会跳过空格、制表符、回车等特殊字符,所有的字符都能被读入。例如下面的程序: #include <iostr
114 0
|
XML C# 数据格式
C#读取写入文件的三种方式
最近对文件的操作比较频繁。这里记录一下常用的几种文件读写的方式。 我这里使用窗体来做测试,例子在文末,可下载。
104 0

热门文章

最新文章