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

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

时间:2023-03-26 12:56:28 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.txtline2lines: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.txtthelloworld$catb.txtthellopython运行后输出如下,因为a的内容.txt和b.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.txtLine1:hellob.txtLine2:python的用法与glob模块完美匹配: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参数,可以指定备份的后缀,比如.bakimportfileinput和fileinput.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行:你好。txt第2行:world$ls-la.txt*-rw-r--r--1MINGstaff1222710:43a.txt-rw-r--r--1MINGstaff4222710:39a.txt.bak5。标准输出重定向替换fileinput.input有个inplace参数,表示是否将标准输出的结果写回文件,默认不替换,请看下面的测试代码importfileinputwithfileinput.input(files=("a.txt",),inplace=True)asfile:print("[INFO]taskisstarted...")forlineinfile:print(f'{fileinput.filename()}line{fileinput.lineno()}line:{line}',end='')print("[INFO]taskisclosed...")运行后会发现for循环体中的打印内容会写回原来的文件和在for循环外的打印没有变化。$cata.txtthelloworld$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做一些更复杂的逻辑,也许你会需要用到下面的方法.如果最后一行读取来自sys.stdin,fileinput.isstdin()返回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直接传这个函数给openhoos导入fileinputfile_url='https://www.csdn.net/robots.txt'withfileinput.input(files=(file_url,),openhook=online_open)asfile:forlineinfile:print(line,end="")运行后,按果然打印出了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="")案例二:读取多个文件的所有行import文件输入importglobforlineinfileinput.input(glob.glob("*.txt")):iffileinput.isfirstline():print('-'*20,f'Reading{fileinput.filename()}...','-'*20)print(str(fileinput.lineno())+':'+line.upper(),end="")情况3:使用fileinput将CRLF文件转换为LFimportsysimportfileinputforlineinfileinput。input(files=('a.txt',),inplace=True):#将Windows/DOS格式的文本文件转换为Linux文件ifline[-2:]=="\r\n":line=line+"\n"sys.stdout.write(line)案例4:配合re做日志分析:取所有包含date的行#--samplefile--:error.logaaa1970-01-0113:45:30错误:****由于系统磁盘空间不足...bbb1970-01-0210:20:30错误:****由于系统内存不足...ccc#---testscript---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:****DuetoSystemDiskspackenotenough...=>1970-01-0210:20:30Error:****DuetoSystemOutofMemory...案例五:使用fileinput实现类似grepimportsysimportreimportfileinputpattern的功能=re.compile(sys.argv[1])forlineinfileinput.input(sys.argv[2]):ifpattern.match(line):print(fileinput.filename(),fileinput.filelineno(),line)$./test.pyimport.*re*.py#在所有py文件中查找包含单词importre的addressBook.py2importreaddressBook1.py10importreaddressBook2.py18importretest.py238importre9.写在最后fileinput是对open函数的重新封装。在只需要读取数据的场景下,fileinput显然比open更加专业和人性化。当然,在其他有写操作的复杂场景下,fileinput就无能为力了。从命名上我们知道这个模块只关注输入(读)而不关注输出(写)。最后介绍一下自己写的两篇在线文档:第一篇:PyCharm中文指南1.0文档整理了100个PyCharm使用技巧,为了让新手直接上手,我花了很多时间录制了上百个GIF动图。有兴趣的可以去网上文档看。第二篇文档:PyCharmBlackMagicGuide1.0文档系统包含了各种Python冷门知识,各种PythonShell的玩法,疯狂的Python技巧,超详细的Python进阶知识解读,非常实用的Python开发技巧等等。