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

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

今天看到了一段代码,值得记录下来。这种写法一般会写在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
相关文章
|
5月前
|
存储 C语言
用二进制方式向文本读写数据
用二进制方式向文本读写数据
31 3
|
5月前
|
C语言
从文件中读取一行
C 语言实例 - 从文件中读取一行。
52 3
|
10月前
|
XML C# 数据格式
C#读取写入文件的三种方式
最近对文件的操作比较频繁。这里记录一下常用的几种文件读写的方式。 我这里使用窗体来做测试,例子在文末,可下载。
82 0
|
11月前
|
NoSQL Java Redis
字节数组流ByteArrayOut(In)putStream使用详解
字节数组流ByteArrayOut(In)putStream使用详解
50 0
|
存储 移动开发 Java
JavaNIO实现按行读取文件操作
在Java编程中,文件操作常常是必不可少的步骤。在对文件进行操作时,按行读取文件是一个常见需求。Java提供了多种方法实现按行读取文件,其中一种方法是使用JavaNIO。
188 0
|
移动开发 Linux Windows
IO流概述分类、字节流写数据、字节流写数据的三种方式及写数据的两个小问题
IO流概述分类、字节流写数据、字节流写数据的三种方式及写数据的两个小问题的简单示例
120 0
IO流概述分类、字节流写数据、字节流写数据的三种方式及写数据的两个小问题
|
Java
字节流写数据加异常处理、字节流读数据、复制文本文件及复制图片
字节流写数据加异常处理、字节流读数据、复制文本文件及复制图片的简单示例
114 0
字节流写数据加异常处理、字节流读数据、复制文本文件及复制图片
|
Java
字符串、字符流中的编码解码问题、字符流写数据的5种方式、字符流读数据的2种方式及复制Java文件
字符串、字符流中的编码解码问题、字符流写数据的5种方式、字符流读数据的2种方式及复制Java文件的简单示例
120 0
字符串、字符流中的编码解码问题、字符流写数据的5种方式、字符流读数据的2种方式及复制Java文件
|
存储 Java
字节缓冲流构造方法、字节流复制视频、字符流及编码表介绍
字节缓冲流构造方法、字节流复制视频、字符流及编码表介绍的简单示例
92 0
字节缓冲流构造方法、字节流复制视频、字符流及编码表介绍
C#编程-35:写入读取文本文件
C#编程-35:写入读取文本文件
110 0