使用 open 函数去读取文件,似乎是所有 Python 工程师的共识。
今天我给大家推荐一个比 open 更好用、更优雅地读取文件方法 -- 使用 fileinput
fileinput 是 Python 的内置模块,但我相信,不少人对它都是陌生的。今天我把 fileinput 的所有的用法、功能进行详细的讲解,并列举了一些非常实用的案例,对于理解和使用它可以说完全没有问题。
当你的 Python 脚本没有传入任何参数时,fileinput 默认会以 stdin 作为输入源
效果如下,不管你输入什么,程序会自动读取并再打印一次,像个复读机似的。
脚本的内容如下
其中 a.txt 的内容如下
helloworld
执行后就会输出如下
需要说明的一点是,fileinput.input() 默认使用 mode='r' 的模式读取文件,如果你的文件是二进制的,可以使用mode='rb' 模式。fileinput 有且仅有这两种读取模式。
从上面的例子也可以看到,我在 fileinput.input 函数中传入了 files 参数,它接收一个包含多个文件名的列表或元组,传入一个就是读取一个文件,传入多件就是读取多个文件。
i
a.txt 和 b.txt 的内容分别是
运行后输出结果如下,由于 a.txt 和 b.txt 的内容被整合成一个文件对象 file ,因此 fileinput.lineno() 只有在读取一个文件时,才是原文件中真实的行号。
如果想要在读取多个文件的时候,也能读取原文件的真实行号,可以使用 fileinput.filelineno() 方法
运行后,输出如下
这个用法和 glob 模块简直是绝配
运行效果如下
fileinput.input 有一个 backup 参数,你可以指定备份的后缀名,比如 .bak
运行的结果如下,会多出一个 a.txt.bak 文件
fileinput.input 有一个 inplace 参数,表示是否将标准输出的结果写回文件,默认不取代
请看如下一段测试代码
运行后,会发现在 for 循环体内的 print 内容会写回到原文件中了。而在 for 循环体外的 print 则没有变化。
利用这个机制,可以很容易地实现文本替换。
附:如何实现 DOS 和 UNIX 格式互换以供程序测试,使用 vim 输入如下指令即可
DOS转UNIX::setfileformat=unixUNIX转DOS::setfileformat=dos
如果只是想要 fileinput 当做是替代 open 读取文件的工具,那么以上的内容足以满足你的要求。
但若要想基于 fileinput 来做一些更加复杂的逻辑,也许你会需要用到如下这几个方法
在 fileinput.input() 中有一个 openhook 的参数,它支持用户传入自定义的对象读取方法。
若你没有传入任何的勾子,fileinput 默认使用的是 open 函数。
fileinput 为我们内置了两种勾子供你使用
返回一个通过 open() 打开每个文件的钩子,使用给定的 encoding 和 errors 来读取文件。使用示例: fi = fileinput.FileInput(openhook=fileinput.hook_encoded("utf-8", "surrogateescape"))
如果你自己的场景比较特殊,以上的三种勾子都不能满足你的要求,你也可以自定义。
这边我举个例子来抛砖引玉下
假如我想要使用 fileinput 来读取网络上的文件,可以这样定义勾子。
直接将这个函数传给 openhoos 即可
运行后按预期一样将 CSDN 的 robots 的文件打印了出来
案例一:读取一个文件所有行
案例二:读取多个文件所有行
案例三:利用fileinput将CRLF文件转为LF
案例四:配合 re 做日志分析:取所有含日期的行
案例五:利用fileinput实现类似于grep的功能
fileinput 是对 open 函数的再次封装,在仅需读取数据的场景中, fileinput 显然比 open 做得更专业、更人性,当然在其他有写操作的复杂场景中,fileinput 就无能为力啦,本身从 fileinput 的命名上就知道这个模块只专注于输入(读)而不是输出(写)。