标签:文件操作

python

python文件操作之目录和路径

在前面的几节中我们讲述了python文件操作,包括基本普通文件和zip压缩包文件, python文件操作 python遍历某个文件夹下的全部文件 python文件操作之zip包操作 在对文件操作过程中往往会对文件路径进行获取,如文件路径所在的目录,文件路径所在的一级目录,通过文件路径截取文件名,文件扩展名等。这就涉及到python中的os模块以及和文件路径相关的os.path模块。 os模块 我们首先来看os模块,官方文档地址在这:https://docs.python.org/2/library/os.html?highlight=os#module-os ,我们来看下os模块中在实际项目中会经常用到的重要的API 首先来看下和文件以及目录操作相关的函数。 该函数用数字模式mode创建一个名为path的目录,mode默认值为0777.如果文件已经存在将会抛出OSError,在windows上会抛出WindowsError: [Error 183] 该系统错误表示当文件已存在时,无法创建该文件。注意当传入的是层级结构的目录时要求前面的目录树都存在,否则会抛出OSError,在windows上会抛出WindowsError: [Error 3],表示系统找不到指定的路径,这也是os.mkdir和os.makedirs的不同点,以如下代码为例: [crayon-5f03aad9669d2424817082/] os.mkdir(path)会抛出异常,因为系统不存在C:\Users\hzhuqi\Deskto层级目录,os.mkdir(path2)可以正确执行,不会抛出异常,因为系统路径存在C:\Users\hzhuqi\Desktop层级目录 根据mode模式创建一个名为path的目录,如果path是一个层级目录树,则会创建每一级中间目录,即使该中间目录不存在(这是和mkdir不同的地方),如果层级目录树下的叶目录已经存在(注意是叶目录)则会抛出OSError。在windows上会抛出WindowsError: [Error 183] 该系统错误表示当文件已存在时,无法创建该文件。以如下代码为例: [crayon-5f03aad9669da619383149/] os.makedirs(path)可以正确执行,即使中间层级目录Deskto不存在,也可以正确创建。os.makedirs(existed_path)会出现异常,如果existed_path在系统磁盘上已经存在的话。 删除path指向的文件,注意只能删除文件,如果path是目录,则会抛出异常,在windows上会出现WindowsError: [Error 5],表示拒绝访问 删除path所指向的目录,注意只能删除空的目录,如果path目录不为空,则会抛出异常,在windows上会出现WindowsError: [Error 2],系统找不到指定的文件 注意该函数只能删除目录,如果传入的path是文件则会抛出异常,在windows上会出现WindowsError: [Error 3],系统找不到指定的路径 删除path路径下的所有目录和子目录,传入的path参数需要是目录,不能是文件,否则会出现异常,传入的目录也要求是空目录,(os.removedirs(‘foo/bar/baz’) will first remove the directory ‘foo/bar/baz’, and then remove ‘foo/bar’ and ‘foo’ if they are empty),如果目录不为空,则会抛出异常,在windows上会出现WindowsError: [Error 145] ,表示目录不为空 和os.rmdir不同的是os.rmdir只会删除path指向的目录,但是removedirs会删除path路径上所有的层级目录,如果目录为空的话   os.path模块 os.path模块官方文档在这:https://docs.python.org/2/library/os.path.html?highlight=os.path#module-os.path,我们来看下os.path模块中在实际项目中会经常用到的重要的API 用来判断文件或者路径在系统平台上是否存在,存在返回True,否则返回False。函数可以说是路径操作中使用频率最高的函数了,因为为了程序的健壮性,在对文件或者目录操作之前都需要先判断该文件或者目录是否存在。 该函数返回的是path路径所在的目录的路径,注意返回的是目录的路径,而不是目录的名称,如以下代码: [crayon-5f03aad9669df013653465/] 则输出为C:\Users\hzhuqi\Desktop,输出是目录所在的路径,而不是目录名Desktop。但是很多时候我们需要根据路径path获取到其所在的目录名称,这个时候我们可以使用os.path.basename(path)函数 该函数返回的是path路径的基本名称,如果path指向的是文件,则返回该文件的文件名(包括扩展名),如果是目录返回该目录名(在Unix平台上返回‘’空字符串,详见python官方文档)。如以下代码: [crayon-5f03aad9669e2470259379/] 那么前面说的根据文件名获取文件所在目录名就很容易解决了,我们可以连续调用两次该函数即可。 该函数根据path路径以文件后缀分隔符.为界限返回一个二元组(root,ext),其中root+ext=path。使用该函数我们可以获取去掉了后缀名的文件名,如果path本身是以.开始则返回(path,”),如splitext(‘.txt’) 返回 (‘.txt’, ”),或者path本身指向的是一个目录而不是文件,如splitext(‘C:\Users\hzhuqi\Desktop’)返回(‘C:\\Users\\hzhuqi\\Desktop’, ”),注意当path指向的是一个文件的时候返回的二元组(root,ext)的第一个元祖root不是文件名,而是文件名所在的路径名,如以下代码: [crayon-5f03aad9669e5076732904/] 输出是C:\Users\hzhuqi\Desktop\test而不是test,也就是说输出是文件名所在的路径,而不是文件名test,所以如果我们要根据path获取文件名的时候我们需要先获取其basename,然后使用splitext函数获取文件名。代码如下: [crayon-5f03aad9669e7085167216/] 输出为去掉了后缀.txt的文件名test 该函数也是使用频率非常高的一个函数,用来将多个path路径连接起来,在路径连接的时候建议使用该函数而不是使用字符串连接方式,如path+os.sep+’path2′     注:本文首次发表于huqi.tech,谢绝转载,如需转载,请注明出处:huqi.tech   扫描下方二维码实时接收最新技术干货推送 扫描二维码实时接收最新技术干货推送,而且会不定期的发布互联网名企内推机会哦!

python

python文件操作之zip包操作

在平时的项目开发中,文件操作是非常频繁的一个场景,前面python文件操作中带领大家学些了基本的文件操作,但是还有一类特殊的文件就是压缩包文件,如jar包,apk包本质上都是压缩包,对这类文件处理要使用python中的zipfile模块。 首先来看一下ZipFile类的定义 然后来看下ZipFile类常用的函数 返回zip包所有的entry名称的list,注意返回的entry名称中包含目录路径,如X/Y/z.txt。 name为传入的entry的名称,注意需要包括目录路径,如某zip包解压后目录层级关系为X/Y/z.txt,则需传入X/Y/z.txt,若直接传入z.txt,因为该zip包中不存在该entry,因此会抛出KeyError错误,如果entry存在,则会返回和该entry名称对应的ZipInfo对象。ZipInfo对象中定义了很多有用的信息,如压缩文件的压缩类型,压缩后的大小,压缩前的大小。常用的属性及其含义如下: ZipInfo.compress_type,该entry的压缩类型,常见的压缩类型包括ZIP_STORED和ZIP_DEFLATED ZipInfo.compress_size,该entry压缩后的大小 ZipInfo.file_size,该entry压缩前的大小 ZipInfo.CRC ,该entry的CRC校验码 除了属性外,ZipInfo还包括一些很有用的函数,如ZipInfo.is_dir()函数可以判断该entry是目录还是文件,如果为目录返回True 解压出名称为member的entry到当前工作路径下,该函数各个参数含义如下: member,待解压的entry名称,同样名称包含路径,如X/Y/z.txt path,解压目录,默认值为None,解压到当前工作目录,如果指定了该值,则会解压到path路径下 pwd,解压的密码,如果该zip在压缩时进行过加密操作,则需要传入该值 将名为filename的文件添加到zip包中,该函数各个参数含义如下: filename,需要添加(写入)到zip包中的文件,通常是一个文件路径的字符串 arcname,添加到zip包中的文件的名称,默认为None,如果不指定该值,则默认采用和filename一样的名称 compress_type,压缩到zip包中时的压缩类型,如ZIP_STORED,ZIP_DEFLATED   虽然ZipFile为我们提供了很多API,但是很遗憾目前的python中ZipFile还未给我们提供一个不解压直接删除zip包中文件的函数,这里我们可以自己定义一个类来继承自ZipFile,然后自己实现直接删除zip包中某一个entry的函数,包括直接删除文件或者文件夹。代码如下: [crayon-5f03aad966dc9653771606/] 在这里我们定义了一个ZipManager类继承自ZipFile类,然后自定义了remove函数用来直接删除zip包中的某一个文件,delete_dir函数来删除文件夹。这样对zip包的操作就比较完整了。 这里实现一个操作就是替换zip包中某个文件,给一个apk文件X.apk,替换文件Y,将apk包中的Z替换为Y,要求替换后,Y的压缩类型要与原apk包中的文件保持一致。之所以选该实例,是因为很显然该实例包括了删除原zip包中的Z,添加Y到zip包中,也就是说该实例可以把ZipFile中的重要函数和属性都用上。当然要用到前面我们扩展的ZipManager类来实现直接删除某一项文件的操作。代码如下: [crayon-5f03aad966dce009342425/] 在这里我们用到了ZipFile的getrinfo函数来获取ZipInfo对象,然后通过ZipInfo.compress_type属性来得到该entry的压缩类型,然后调用我们扩展的ZipManager的remove函数直接删除该entry,最后调用write函数向zip包中添加文件,同时指定添加的文件的名称和压缩类型,这个实例可以说是zip包操作中综合性最高的一个操作。     注:本文首次发表于huqi.tech,请勿转载,如需转载,请注明出处:huqi.tech   扫描下方二维码实时接收最新技术干货推送 扫描二维码实时接收最新技术干货推送,而且会不定期的发布互联网名企内推机会哦!  

python

python遍历某个文件夹下的全部文件

在前面的一小节中,我们谈到了对文件的读写操作,这一节我们谈谈使用python遍历某个文件夹下的全部文件,因为在实际的项目场景中这种情况非常常见,如在apk的逆向工程中可能需要在把dex文件反编译后产生的smali文件中查找某一特定的字符串,然后进行替换操作。这个场景很显然就涉及到了对某一文件夹下所有文件进行遍历的过程。这个过程很显然是对文件,目录,路径进行操作,而这些很显然是属于操作系统管理的范畴,因此这些功能被定义在了python中的os模块和os.path模块,使用前需要import相应的模块。这一小节就讲讲python中这两个模块常用的和文件操作相关的重要函数。 应用场景:将某一文件夹及其子文件夹下的全部的txt文件中的某个字符串替换为指定的字符串,这个实例综合了上一节和这一节的内容,在实际项目的文件操作中很常见。 [crayon-5f03aad966fc2526121687/]  

python

python文件操作

在任何一门高级语言中,文件I/O操作是非常重要的一个模块,python中的文件操作和C语言中非常类似,也很简单,虽然很简单,但是文件操作中也有很多需要主要的地方,尤其是读写效率的问题。 和c语言一样python使用open函数打开一个文件,该函数定义如下: [crayon-5f03aad9672d3631971686/] 当然对于我们而言通常不需要关心那么多参数,通常我们只关心最前面的两个参数,file和mode,file表示的是要打开的文件,通常是一个包含绝对路径的字符串,第二个参数mode表示打开的访问方式,默认值为r,表示只读。第二个参数的常用的取值和对应含义如下: r 只读模式,也是默认的打开模式,如果文件不存在将抛出异常 w只写模式,不能读取文件内容,如果文件存在将清空文件内容,如果不存在则创建 a追加模式,可读,文件存在则在文件末尾追加内容,不存在则创建 +更新模式,可读可写,通常与r,w,a连用,打开一个磁盘文件用于更新(进行读写操作) r+读写模式,即r与+模式的组合,如果文件不存在将抛出异常 w+读写模式,与r+不同的是该模式会清空文件已存在的内容,且如果文件不存在会创建该文件 可以看到这和c语言中是一模一样的,通常我们在实际项目中使用的较多的模式是‘r+’,’w+’或者’a+’。open函数的使用很简单,和C语言一样: [crayon-5f03aad9672db956771810/] 但是正如前面说到的,以r或者r+模式打开问的时候如果文件不存在程序会抛出异常No such file or directory,因此上面的写法显然是不对的,我们必须对这种可能出现的情况进行处理,因此通常我们会使用try/except语句,像下面这样,个人觉得java语言在这方面设计的很好,对于可能会出现IO异常的操作,java会要求必须try/catch否则IDE会自动提示错误。而python如果不处理不会提示错误,但运行时可能出错。 [crayon-5f03aad9672df061889691/] 在上面这段代码中我们对可能出现的异常进行捕获,然后处理(该代码中是使用print打印出出错原因),即使出现异常程序仍可以顺序往下执行,如果不这么做那么当打开文件失败(如文件不存在)时程序会终止退出,因此文件操作时必须要对可能出现的异常进行捕获处理。 那么上述代码是否就是合理的代码呢?我们知道,当我们打开一个文件进行操作后,最好是在不需要读写的时候使用close()函数关闭该操作。因此一个规范的打开文件的操作应该是这样的: [crayon-5f03aad9672e1324461169/] 注意在finally语句块中,调用close()关闭读写操作之前,要对该文件对象进行判空操作,因为在open函数打开文件的时候可能失败,即出现异常,此时fileObject为空,但finally块不管是否出现异常是一定会执行的,因此需要先判空再操作,这基本上才是打开一个文件的规范代码,但是每次这么写太麻烦,因此python为我们提供了with as语句。 [crayon-5f03aad9672e3345349162/] 使用with as语句在该语句块结束的时候文件会自动关闭,即使出现异常也会close() [crayon-5f03aad9672e5771642814/] 但是注意with as 语句打开文件,只是帮我们自动处理了close()的调用而已,异常的捕获还是需要我们自己处理,因此对文件进行打开操作时使用with as且捕获异常是一个好的习惯。 文件的读 文件的读主要涉及到三个重要的函数read(),readline()和readlines() read(size):如果不指定size的大小,此时size默认为-1,事实上此时read()会调用readall()函数,此时会一次性读取文件的全部内容,因此如果文件比较大,会占用非常大的内存,程序将会运行的十分缓慢,效率较低,此时通常不会直接使用read()而是会指定一个size参数,每次读取size个字节的内容。 readline():默认读取一行,包括行结束符,因此如果需要得到不包含行结束符的数据的话需要程序员自己处理。 readlines():该函数会读取文件所有的行然后把结果作为一个字符串列表返回 通过这三个函数的描述我们知道,如果读取的文件不是很大的话,我们通常使用read()或者readLines()函数一次性读取文件的全部内容,而不是使用readLine()一次读取一行,因此这样效率较慢,如果文件比较大,我们可以使用readLine()或者read(size)的方式一次读取一行或者size个字节进行处理,否则会很占内存。另外这三个函数不会处理行结束符,因此如果我们希望得到的数据不包含行结束符(windows下为’\n’,mac下为’\r’)的时候,需要我们手动处理,以readLines()为例,代码如下: data=[line.strip() for line in fileObject.readlines()] 其中strip()如果不指定参数的话,默认去除首尾空白符包括(‘\n’, ‘\r’, ‘\t’, ‘ ‘) 文件的写 文件的写和读是一一对应的关系,但是不存在writeline()函数,只存在write()和writelines(),含义和文件的读是一一对立的,因此也很容易理解。 write(size):向文件中写入size个字节 writelines():向文件中一次写入一个字符串列表 需要注意的是write()和writelines()不会写入行结束符,因此我们向文件中写入内容是需要自己处理行结束符。 在对文件操作时一个常用的场景就是先读取文件的全部内容到一个字符串列表中,然后对该字符串列表中的数据进行处理后写回原文件,把之前文件的内容替换掉,这种模式只能使用’r+’模式打开,那么这就存在一个问题就是之前因为读取了文件的内容,因此此时文件指针已经指向了文件的末尾,因此如果我们直接调用write()或者writelines()的话,此时的效果事实上相当于追加模式,会写到原文件的末尾,因此此时我们需要移动文件指针到文件开始位置,然后写入数据。文件指针的移动使用seek()函数。 seek(offset[,whence]) 该函数的第一个参数表示相对某个位置的偏移量,这里所说的相对某个位置就是第二个参数的含义,第二个参数可以取0,1,2三个值,0表示从文件开头开始算起,1表示从当前位置开始算起,2表示从文件末尾算起。默认值为0,从文件开始位置算起。因此代码如下: [crayon-5f03aad9672ea003933506/] 使用场景:在很多场合下我们需要读取一个文件中的内容,然后对该内容中的某些字符串进行特定处理,如替换某些关键词,然后将处理后的结果写回到原文件。本实例展示的是从一个记录了baidu,alibaba,tencent,jd,netease,360等知名互联网企业的文本文件中找出带有alibaba的行,然后替换为tencent.最后将结果写回原文件。 [crayon-5f03aad9672ed784759879/] 这个实例是项目中进行文件操作是经常会遇到的,而且也把前面所总结的知识点全部用到了,包括前面说的对文件操作使用with as,使用try/except对可能出现的异常进行处理等一些好的习惯。 对文件操作尽量使用with as,确保文件操作会调用close() 文件操作一定要使用try/except对可能出现的异常进行处理 如果操作的文件不大的话使用readlines()一次性读取全部文件效率较高,此时不要使用readline(),如果文件较大使用read(size)或者readline()进行处理,减少对内存的消耗 在向原操作文件写回处理的内容的时候注意文件指针的位置,某些场景下需要调用seek(0)回到文件开始位置再写入。