当前位置: 首页 > 科技观察

了解这一点,您可以使用Python完成超过99%的文件操作

时间:2023-03-14 20:00:24 科技观察

处理文件是我们每天最常见的任务之一。Python有几个内置模块用于执行文件操作,例如读取文件、移动文件、获取文件属性等。本文总结了您需要了解的许多功能,涵盖了Python中最常见的文件操作和良好实践。这是您将在本文中看到的框图/功能图。要了解有关每个操作的更多信息,请继续阅读。图1.xiaoxuguo提供1.打开和关闭文件当您想要读取或写入文件时,您需要做的第一件事就是打开文件。Python有一个open内置函数,可以打开一个文件并返回一个文件对象。文件对象的类型取决于打开文件的模式。它可以是文本文件对象、原始二进制文件和缓冲二进制文件。每个文件对象都有read()和write()等方法。这个代码块有问题,你能识别出来吗?我们稍后再讨论。file=open("test_file.txt","w+")file.read()file.write("anewline")Python文档列出了所有可能的文件模式。表中列出了最常见的模式。一个重要的规则是任何与w关联的模式都将首先截断文件(如果存在),然后创建一个新文件。如果您不想覆盖文件,请谨慎使用此模式,并尽可能使用追加模式。modemeaningr以读方式打开(默认)r+以读写方式打开(文件指针位于文件开头)w以写方式打开(如果存在则截断文件)w+以读写方式打开(如果存在则截断文件)a打开写操作(追加到文件末尾(如果存在,文件指针在文件末尾)上一个代码块中的问题是我们只打开了文件,但没有关闭它。在处理文件时始终关闭文件很重要。拥有一个打开的文件对象可能会导致不可预测的行为,例如资源泄漏。有两种方法可以确保正确关闭文件。1.使用close()第一种方法是显式使用close()。一个好的做法是将它放在最后,这样我们就可以确保在任何情况下都会关闭该文件。它使代码更清晰,但另一方面,开发人员应该承担责任并且不要忘记将其关闭。try:file=open("test_file.txt","w+")file.write("anewline")exceptionExceptionase:logging.exception(e)finally:file.close()2.使用上下文管理器,设置open(...)设置为f第二种方法是使用上下文管理器。如果您不熟悉上下文管理器,请查看DanBader的上下文管理器和Python中的“with”语句。与open()一起使用,因为f语句实现了__enter__和__exit__方法来打开和关闭文件。此外,它将try/finally语句包装在上下文管理器中,这意味着我们永远不会忘记关闭文件。withopen("test_file","w+")asfile:file.write("anewline")这个上下文管理器解决方案总是比close()更好吗?这取决于你在哪里使用它。以下示例实现了将50,000条记录写入文件的3种不同方式。从输出中可以看出,与其他函数相比,use_context_manager_2()函数的性能极低。这是因为with语句在一个单独的函数中,基本上是为每条记录打开和关闭文件。这种昂贵的I/O操作会极大地影响性能。def_write_to_file(file,line):withopen(file,"a")asf:f.write(line)def_valid_records():foriinrange(100000):ifi%2==0:yieldidefuse_context_manager_2(file):forlinein_valid_records():_write_to_file(文件,str(line))defuse_context_manager_1(file):withopen(file,"a")asf:forlinein_valid_records():f.write(str(line))defuse_close_method(file):f=open(file,"a")forlinein_valid_records():f.write(str(line))f.close()use_close_method("test.txt")use_context_manager_1("test.txt")use_context_manager_2("test.txt")#Finished'use_close_method'in0.0253secs#Finished'use_context_manager_1'in0.0231secs#Finished'use_context_manager_2'in4.6302secs2。读写文件打开文件后,您必须读取或写入文件。文件对象提供了三种读取文件的方法,分别是read()、readline()和readlines()。默认情况下,read(size=-1)返回文件的全部内容。如果文件大于内存,可选参数size可以帮助您限制以字符(文本模式)或字节(二进制模式)返回的大小。readline(size=-1)返回整行,包括末尾的字符\n。如果size大于0,它将返回行中的最大字符数。readlines(hint=-1)返回列表中文件的所有行。可选参数hint表示如果返回的字符数超过hint,则不返回任何行。在这三种方法中,read()和readlines()的内存效率较低,因为默认情况下,它们以字符串或列表的形式返回完整的文件。一种更有效的遍历内存的方法是使用readline()并让它停止读取,直到返回一个空字符串。空字符串“”表示指针已到达文件末尾。withopen('test.txt','r')asreader:line=reader.readline()whileline!="":line=reader.readline()print(line)在写法方面,有两种方法write()和写线()。顾名思义,write()是写一个字符串,writelines()是写一个字符串列表。在末尾添加\n是开发人员的责任。withopen("test.txt","w+")asf:f.write("hi\n")f.writelines(["thisisaline\n","thisisanotherline\n"])#>>>cattest.txt#hi#thisisaline#thisisanotherline如果要将文本写入特殊文件类型(如JSON或csv),则应在文件对象之上使用Python内置模块json或csv。importcsvimportjsonwithopen("cities.csv","w+")asfile:writer=csv.DictWriter(file,fieldnames=["city","country"])writer.writeheader()writer.writerow({"city":"阿姆斯特丹","country":"荷兰"})writer.writerows([{"city":"柏林","country":"德国"},{"city":"上海","country":"中国"},])#>>>catcities.csv#city,country#Amsterdam,Netherlands#Berlin,Germany#Shanghai,Chinawithopen("cities.json","w+")asfile:json.dump({"city":"阿姆斯特丹”,“国家”:“荷兰”},文件)#>>>catcities.json#{“城市”:“阿姆斯特丹”,“国家”:“荷兰”}1。当我们打开文件时将光标移动到文件内部,我们得到一个指向特定位置的文件处理程序。在r和w模式下,处理程序指向文件的开头。在一种模式下,处理程序指向文件末尾。(1)tell()和seek()当我们从文件中读取时,指针会移动到下一次读取开始的地方,除非我们告诉指针移动。您可以使用2种方法来执行此操作:tell()和seek()。tell()返回指针的当前位置,作为从文件开头算起的字节/字符数。seek(offset,whence=0)将处理程序移动到一个位置,使字符远离wherece。location可以是:0:从文件头开始1:从当前位置开始2:从文件尾开始文本模式下,wherece只能为0,offset必须≥0。withopen("text.txt","w+")asf:f.write("0123456789abcdef")f.seek(9)print(f.tell())#9(pointermovesto9,nextreadstartsfrom9)print(f.read())#9abcdef2。了解文件状态操作系统上的文件系统可以告诉您很多关于文件的有用信息。例如,文件的大小、创建时间和修改时间。要在Python中获取此信息,您可以使用os或pathlib模块。实际上,os和pathlib有很多共同点。pathlib是一个比os.pathlib更面向对象的模块。3.操作系统获得完整状态的一种方法是使用os.stat("test.txt")。它返回一个包含许多统计信息的结果对象,例如st_size(以字节为单位的文件大小)、st_atime(最近访问的时间戳)、st_mtime(最近修改的时间戳)等。print(os.stat("text.txt"))>>>os.stat_result(st_mode=33188,st_ino=8618932538,st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=16,st_atime=1597527409,st_mtime=1597527409,st_ctime=15979)5274使用os.path单独获取统计信息。os.path.getatime()os.path.getctime()os.path.getmtime()os.path.getsize()3.路径库获取完整状态的另一种方法是使用pathlib.Path("text。TXT”)。统计()。它返回与os.stat()相同的对象。print(pathlib.Path("text.txt").stat())>>>os.stat_result(st_mode=33188,st_ino=8618932538,st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=16,st_atime=1597528703,st_mtime=1597528703,st_ctime=1597528703)在后面的章节中,我们将比较os和pathlib的更多方面。4.复制、移动和删除文件Python有许多内置模块来处理文件移动。在您相信Google返回的第一个答案之前,您应该知道不同的模块选择会导致不同的性能。一些模块会阻塞线程直到文件移动完成,而其他模块可能会异步执行。1.关闭shutil是最著名的移动、复制和删除文件和文件夹的模块。它提供了4种方法来复制文件。copy()、copy2()和copyfile()。copy()和copy2():copy2()与copy()非常相似。不同的是copy2()还会复制文件的元数据,比如上次访问时间,上次修改时间。但根据Python文档,由于操作系统的限制,即使copy2()也无法复制所有元数据。shutil.copy("1.csv","copy.csv")shutil.copy2("1.csv","copy2.csv")print(pathlib.Path("1.csv").stat())打印(pathlib.Path("copy.csv").stat())print(pathlib.Path("copy2.csv").stat())#1.csv#os.stat_result(st_mode=33152,st_ino=8618884732,st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=11,st_atime=1597570395,st_mtime=1597259421,st_ctime=1597570360)#copy.csv#os.stat_result(st_mode=33152,st_ino8618983930,st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=11,st_atime=1597570387,st_mtime=1597570395,st_ctime=1597570395)#copy2.csv#os.stat_result=9=3dev72st_158,st_nlink=1,st_uid=501,st_gid=20,st_size=11,st_atime=1597570395,st_mtime=1597259421,st_ctime=1597570395)2.367/5000copy()和copyfile():copy()将是新文件的权限设置为与原始文件相同,但copyfile()不会复制其权限模式。其次,copy()的目标可以是一个目录。如果存在同名文件,则覆盖该文件,否则创建新文件。但是,copyfile()的目的地必须是目标文件名。shutil.copy("1.csv","copy.csv")shutil.copyfile("1.csv","copyfile.csv")print(pathlib.Path("1.csv").stat())打印(pathlib.Path("copy.csv").stat())print(pathlib.Path("copyfile.csv").stat())#1.csv#os.stat_result(st_mode=33152,st_ino=8618884732,st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=11,st_atime=1597570395,st_mtime=1597259421,st_ctime=1597570360)#copy.csv#os.stat_result(st_mode=33152,st_ino8618983930,st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=11,st_atime=1597570387,st_mtime=1597570395,st_ctime=1597570395)#resultfile.csv#permission(st_modest8,891.=331)st_dev=16777220,st_nlink=1,st_uid=501,st_gid=20,st_size=11,st_atime=1597570387,st_mtime=1597570395,st_ctime=1597570395)shutil.csvfile("1../source")#IsADirectoryError:[Errno21]Isadirectory:'./source'3.osos模块有一个system()函数,允许您在子shell中执行命令。您需要将命令作为参数传递给system()。这与在操作系统上执行的命令具有相同的效果。对于移动和删除文件,您还可以使用os模块中的专用函数。#copyos.system("cp1.csvcopy.csv")#rename/moveos.system("mv1.csvmove.csv")os.rename("1.csv","move.csv")#deleteos.system("rmmove.csv")4.异步复制/移动文件到目前为止,解决方案一直是同步的,这意味着如果文件很大并且移动需要更多时间,程序可能会阻塞。如果要使程序异步,可以使用线程、多处理或子进程模块使文件操作在单独的线程或单独的进程中运行。importthreadingimportsubprocessimportmultiprocessingsrc="1.csv"dst="dst_thread.csv"thread=threading.Thread(target=shutil.copy,args=[src,dst])thread.start()thread.join()dst="dst_multiprocessing.csv"process=multiprocessing.Process(target=shutil.copy,args=[src,dst])process.start()process.join()cmd="cp1.csvdst_subprocess.csv"status=subprocess.call(cmd,shell=正确)5.搜索文件复制和移动文件后,您可能需要搜索与特定模式匹配的文件名。Python提供了许多内置函数可供选择。1.glob模块根据Unixshell使用的规则查找所有匹配指定模式的路径名。它支持*?等通配符。[].glob.glob("*.csv")在当前目录中搜索所有扩展名为csv的文件。使用glob模块,也可以在子目录中搜索文件。>>>importglob>>>glob.glob("*.csv")['1.csv','2.csv']>>>glob.glob("**/*.csv",recursive=True)['1.csv','2.csv','source/3.csv']2.osos模块非常强大,它基本上是做文件操作的。我们可以简单地使用os.listdir()来列出目录中的所有文件,并使用file.endswith()和file.startswith()来检测模式.如果你想遍历一个目录,使用os.walk().importosforfileinos.listdir("."):iffile.endswith(".csv"):print(file)forroot,dirs,filesinos.walk("."):forfileinfiles:iffile.endswith(".csv"):print(file)3.pathlibpathlib和glob模块有类似的功能,也可以递归搜索文件名。相比之前基于os的方案,pathlib的代码更少,并提供了更多面向对象的解决方案。六、使用文件路径播放文件路径是我们执行的另一个常见任务。它可以获取相对path和文件的绝对路径。还可以连接多个Path,查找父目录等。1.相对路径和绝对路径os和pathlib都提供了获取文件或目录的相对路径和绝对路径的功能。importosimportpathlibprint(os.path.abspath("1.txt"))#absoluteprint(os.path.relpath("1.txt"))#relativeprint(pathlib.Path("1.txt").absolute())#absoluteprint(pathlib.Path("1.txt"))#relative2。加入路径这就是我们如何独立于环境加入os和pathlib中的路径。pathlib使用斜杠来创建子路径。importosimportpathlibprint(os.path.join("/home","file.txt"))print(pathlib.Path("/home")/"file.txt")3.获取父目录dirname()在os函数中获取父目录,而在pathlib中你可以直接使用Path()。parent获取父文件夹。importosimportpathlib#relativepathprint(os.path.dirname("source/2.csv"))#sourceprint(pathlib.Path("source/2.csv").parent)#source#absolutepathprint(pathlib.Path("source/2.csv").resolve().parent)#/Users/<...>/project/sourceprint(os.path.dirname(os.path.abspath("source/2.csv")))#/Users/<...>/project/source4.OSPATHLIBRARY最后但同样重要的是,我想简单介绍一下os和pathlib。正如Python文档中所述,pathlib是一个比os.pathlib更面向对象的解决方案。它将每个文件路径表示为适当的对象,而不是字符串。这给开发人员带来了很多好处,例如更容易连接多个路径、在不同操作系统之间更加一致以及直接从对象访问方法。希望本文能提高您处理文件的效率。英文原文链接:https://towardsdatascience.com/knowing-these-you-can-cover-99-of-file-operations-in-python-84725d82c2df