当前位置: 首页 > 后端技术 > Python

没想到吧?这个比open更适合读取文件

时间:2023-03-26 11:10:30 Python

使用open函数读取文件似乎是所有Python工程师的共识。今天要给大家推荐一个比open更好用也更优雅的读取文件的方法——使用fileinputfileinput是Python的内置模块,但相信很多人对它比较陌生。今天详细讲解了fileinput的所有用法和作用,并列举了一些非常实用的案例。理解和使用都没有问题。1.从标准输入读取当你的Python脚本没有传入任何参数时,fileinput默认会使用stdin作为输入源#demo.pyimportfileinputforlineinfileinput.input():print(line)效果如下,无论你输入什么,程序都会自动读取并打印一遍,就像复读机一样。$pythondemo.pyhellohellopythonpython2。打开单个文件打开单个文件,只需在文件中输入一个文件名importfileinputwithfileinput.input(files=('a.txt',))asfile:forlineinfile:print(f'{fileinput.filename()}line{fileinput.lineno()}:{line}',end='')其中a.txt内容如下helloworld执行后输出如下$pythondemo.pya.txtLine1:helloa.txt第2行:world需要注意的一点是fileinput.input()默认使用mode='r'来读取文件。如果你的文件是二进制的,你可以使用mode='rb'模式。fileinput有且只有这两种读取模式。3、批量打开多个文件从上面的例子可以看出,我在fileinput.input函数中传入了files参数,它接收一个包含多个文件名的列表或元组,传入一个就是读取一个文件,传入多个文件意味着读取多个文件。importfileinputwithfileinput.input(files=('a.txt','b.txt'))asfile:forlineinfile:print(f'{fileinput.filename()}line{fileinput.lineno()}:{line}',end='')a.txt和b.txt的内容分别是$cata.txthelloworld$catb.txtthellopython输出结果如下,因为a.txt和b.txt的内容。txt被集成到一个文件目标文件中,所以fileinput.lineno()只有在读取文件时才是原始文件中的真实行号。$pythondemo.pya.txt第1行:helloa.txt第2行:worldb.txt第3行:hellob.txt第4行:如果python要读取多个文件,也可以读取原始文件的真实行号,您可以使用fileinput.filelineno()方法importfileinputwithfileinput.input(files=('a.txt','b.txt'))asfile:forlineinfile:print(f'{fileinput.filename()}Line{fileinput.filelineno()}:{line}',end='')运行后输出如下$pythondemo.pya.txtLine1:helloa.txtLine2:worldb.txt第1行:hellob.txt第2行:python的用法和glob模块是绝配importfileinputimportglobforlineinfileinput(glob.glob("*.txt")):print('-'*20,f'Reading{fileinput.filename()}...','-'*20)print(str(fileinput.lineno())+':'+line.upper(),end=""),运行效果如下$pythondemo.py--------------------Readingb.txt...----------------------1:HELLO2:PYTHON--------------------Readinga.txt...--------------------3:你好4:世界4。而读取备份文件fileinput.input有一个backup参数,可以指定备份后缀名,比如.bakimportfileinputwithfileinput.input(files=("a.txt",),backup=".bak")asfile:forlineinfile:print(f'{fileinput.filename()}line{fileinput.lineno()}:{line}',end='')运行结果如下,会多出一个a.txt.bak文件$ls-la.txt*-rw-r--r--1MINGstaff1222710:43a.txt$pythondemo.pya.txt第1行:helloa.txt第2行:world$ls-la.txt*-rw-r--r--1MINGstaff1222710:43a.txt-rw-r--r--1MINGstaff4222710:39a.txt.bak5.标准输出重定向替换fileinput.input有一个inplace参数,表示是否将标准输出的结果写回到文件中。默认不替换,请看下面一段测试代码..")forlineinfile:print(f'{fileinput.filename()}line{fileinput.lineno()}:{line}',end='')print("[INFO]taskisclosed...")运行后会在for循环体中找到for循环的打印内容会写回到原来的文件,而for循环外的打印不会改变。$cata.txthelloworld$pythondemo.py[INFO]taskisstarted...[INFO]taskisclosed...$cata.txta.txtline1:helloa.txtline2:worldusethisMechanismfor简单的文本替换。importsysimportfileinputforlineinfileinput.input(files=('a.txt',),inplace=True):#将Windows/DOS格式的文本文件转换为Linux文件ifline[-2:]=="\r\n":line=line+"\n"sys.stdout.write(line)附:程序测试如何实现DOS和UNIX格式互换,使用vim输入如下命令将DOS转UNIX::setfileformat=unixUNIX到DOS::setfileformat=dos6。我要介绍的方法如果你只是想把fileinput作为一个工具来代替opentoreadfiles,那么以上内容已经足够满足你的要求了。fileinput.filenam()\返回当前正在读取的文件名。返回None直到第一行被读取。fileinput.fileno()\返回表示为整数的当前文件“文件描述符”。当文件未打开时(在第一行和文件之间),返回-1。fileinput.lineno()\返回已读取的累计行号。返回0,直到读取第一行。读取最后一个文件的最后一行后,返回该行的行号。fileinput.filelineno()\返回当前文件中的行号。返回0,直到读取第一行。读取最后一个文件的最后一行后,返回该文件中该行的行号。但是如果你想根据fileinput做一些更复杂的逻辑,也许你会需要用到下面的方法fileinput.isfirstline()\如果刚才读取的行是它所在文件的第一行,则返回True,否则返回错误的。fileinput.isstdin()\如果读取的最后一行来自sys.stdin,则返回True,否则返回False。fileinput.nextfile()\关闭当前文件,以便下一次迭代从下一个文件(如果存在)读取第一行;未从此文件读取的行将不计入累积行数。在读取下一个文件的第一行之前,文件名不会改变。该函数在读取第一行后才会生效;它不能用于跳过第一个文件。读取完最后一个文件的最后一行后,该函数将不再有任何作用。fileinput.close()\关闭序列。7、更高级的玩法,在fileinput.input()中有一个openhook参数,支持用户传入自定义的对象读取方法。如果不传递任何钩子,fileinput默认使用open函数。fileinput为我们提供了两个内置的钩子,您可以使用fileinput.hook_compressed(*filename*,*mode*)来使用gzip和bz2模块透明地打开gzip和bzip2压缩文件(扩展名为'.gz'和'.bz2'来识别)。如果文件扩展名不是“.gz”或“.bz2”,则文件以正常方式打开(即使用open()且不进行任何解压缩)。示例用法:fi=fileinput.FileInput(openhook=fileinput.hook_compressed)fileinput.hook_encoded(*encoding*,*errors=None*)返回一个钩子,它通过open()打开每个文件,使用给定的编码和错误读取文件.例子:fi=fileinput.FileInput(openhook=fileinput.hook_encoded("utf-8","surrogateescape"))如果你自己的场景比较特殊,上面三个hook都不能满足你的要求,你也可以自定义。这里我举个例子展开讨论。如果我想使用fileinput来读取网络上的文件,我可以这样定义钩子。先用requests把文件下载到本地再用open读取defonline_open(url,mode):importrequestsr=requests.get(url)filename=url.split("/")[-1]withopen(filename,'w')asf1:f1.write(r.content.decode("utf-8"))f2=open(filename,'r')returnf2直接传这个函数给openhookimportfileinputfile_url='https://www.csdn.net/robots.txt'withfileinput.input(files=(file_url,),openhook=online_open)asfile:forlineinfile:print(line,end="")运行后,press果然打印出了CSDN的robots文件。用户代理:*禁止:/scripts禁止:/public禁止:/css/禁止:/images/禁止:/content/禁止:/ui/禁止:/js/禁止:/scripts/禁止:/article_preview.html*Disallow:/tag/Disallow:/*?*Disallow:/link/站点地图:https://www.csdn.net/sitemap-aggpage-index.xml站点地图:https://www.csdn.net/article/sitemap.txt8.列举一些实际案例案例一:读取一个文件的所有行importfileinputforlineinfileinput.input('data.txt'):print(line,end="")情况二:读取多个文件的所有行读取{fileinput.filename()}...','-'*20)print(str(fileinput.lineno())+':'+line.upper(),end="")案例3:使用fileinputconvertsCRLFfilestoLFimportsysimportfileinputforlineinfileinput.input(files=('a.txt',),inplace=True):#将Windows/DOS格式的文本文件转换为Linux文件ifline[-2:]=="\r\n":line=line+"\n"sys.stdout.write(line)案例四:配合re进行日志分析:取所有带日期的行#--samplefile--:error.logaaa1970-01-0113:45:30错误:****由于系统磁盘空间不足...bbb1970-01-0210:20:30错误:****由于系统内存不足...ccc#---测试脚本---importreimportfileinputimportsyspattern='\d{4}-\d{2}-\d{2}\d{2}:\d{2}:\d{2}'forlineinfileinput.input('error.log',backup='.bak',inplace=1):ifre.search(pattern,line):sys.stdout.write("=>")sys.stdout.write(line)#---测试结果---=>1970-01-0113:45:30Error:****DuetoSystemDiskspacklenotenough...=>1970-01-0210:20:30Error:****DuetoSystemOutofMemory...案例五:使用fileinput实现类似grep的功能importsysimportreimportfileinputpattern=re.compile(sys.argv[1])forline在fileinput.input(sys.argv[2])中:ifpattern.match(line):print(fileinput.filename(),fileinput.filelineno(),line)$./demo.pyimport.*re*.py#在所有含有importre的py文件中查找addressBook.py2importreaddressBook1.py10importreaddressBook2.py18importretest.py238importre9最后写的fileinput是对open函数的重新封装,只需要读取数据的场景,fileinput显然比open更加专业和人性化。当然,在其他有写操作的复杂场景下,fileinput就无能为力了。从fileinput这个名字我们就知道这个模块只专注于输入(读)而不是输出(写)以上就是本次分享的全部内容。觉得文章还不错的话,请关注公众号:Python编程学习圈,每日干货分享,发送“J”还能收到海量学习资料,内容涵盖Python电子书、教程、数据库编程、Django、爬虫、云计算等。或者去编程学习网了解更多编程技术知识。