python渐进-文件

文件操作是编程语言的一项重要能力。包括了文件的读写操作,文件以及目录的操作等。下面就逐一介绍。

10.1 文件的打开

在python中,使用open语句打开一个文件。演示的代码如下。

f=open('myfile.txt','r')

上述的语句当中,'myfile.txt'是文件的名称,f是获取到的文件句柄,在以后的文件读写操作都需要通过这个句柄进行。

如果这个文件不是绝对路径的话,那么python会在sys.path里面列出的路径集合中寻找这个文件;如果是绝对路径,例如'/Users/chenosanabin/Documents/myfile.txt'或者‘D:\\myfile.txt’这样的绝对路径,python会直接用这个绝对路径中访问文件。

文件路径也是乱码频发的一个源头。linux、windows、mac系统对文件路径的中文编码均不相同。windows系统使用原生的unicode编码对文件路径中的中文编码;linux系统的文件路径编码可以自行设置;mac系统则使用utf8对文件路径进行编码。

在不同的系统中,一个相同的文件路径需要进行不同的编码才能够访问到。很多人为了避免麻烦,会自觉地避免把文件放在中文目录,避免文件名中含有中文。

实际上如果知道了背后的原理,是可以很妥善地处理中文路径的问题的。一个系统的文件路径的编码,可以通过sys.getfilesystemencoding()这个函数获取到。

调用这个函数后,windows系统会返回'mbcs',这个是原生unicode编码;unix系统是用户自行设置,可能返回不同编码;mac系统会返回'utf8'。

一个文件路径,在程序里面最好使用unicode存储,然后根据 sys.getfilesystemencoding()这个函数返回的值,通过encode把unicode转化成相应的编码,就可以正确访问到文件了。演示的代码如下:

#coding=utf8

import sys

filepathencoding=sys.getfilesystemencoding()

filename=u'中文文件.txt'

if filepathencoding!='mbcs':

filename=filename.encode(filepathencoding)

f=open(filename,'r')

使用open()来打开一个文件,需要考虑文件的读写模式问题。如果是只读模式,那么就不能够修改文件;如果是写模式,那么就可写可读了。这是为了防止对文件的误操作加入的功能。

open()的第二个参数就是设置读写模式的。其中'r'是只读;'w'是可写的;'a'是增量写入;'r+'是可读可写。如果选择了'w'模式,那么写入的时候会从文件头开始写入;而选择了'a'模式,写入的时候会从文件的末尾开始写入。

在windows系统里面,文本文件和非文本文件是有区别的。对一个文本文件进行写入的时候,换行符会被转成系统特定符号。这个事情是windows系统做的,会破坏文件的结构。对于图片文件或者音视频文件,这种修改会导致文件无法打开。因此在读写图片和音视频文件的时候,需要特别声明这是非文本文件。此时需要设置文件使用'b'模式打开,也就是二进制文件。'b'模式和之前提到的读写模式组合,可以变成'rb','wb','ab' 等等。'b'模式是为了windows系统特别存在,对于unix体系的系统来说,'b'模式是透明的。

在文件的读写完毕后,一个好的习惯是,把文件的句柄关闭,释放文件资源。文件的关闭使用close()方法。

f.close()

在python里有一个with语句,离开with语句的时候,会自动就调用了close()。

一个简单的使用with语句操作文件的代码如下:

with open(filename,'r') as f:

print(f.read())

with语句把open()语句返回的文件句柄赋值给f,接着所有的文件操作都可以在with语句下面进行。当离开with语句,f的close()操作会被自动调用,不再需要自行处理了。

10.2 文件的读写

要读取一个文件,有三种方式。一行一行读,一块一块读,全部读。

如果文件大小合适,不超过python默认的缓存,操作系统的内存也装得下,全部读进来是可以的。这个时候的操作就很简单。使用f.read()或者f.readlines()就可以了。

f.read()把读进来的内容看作是一个字符串。而f.readlines()把读进来的内容看作是一个list,list里面的每个item都是一行。

比如一个文件,包含了下面几行

1

2

3

4

使用f.read()的话,结果是

'1\n2\n3\n4\n'

使用f.readlines()的话,结果是

['1\n', '2\n', '3\n', '4\n']

无论是f.read()还是f.readlines(),换行符都不会被处理。使用readlines()的时候,要记得自行处理换行符。

如果文件很大,无法一下子读进来,可以采用一块一块读,或者一行一行读。

使用f.read(readsiez)每次读取readsize大小的内容。循环读取文件直到读入的内容是空的。演示代码如下:

r=f.read(1)

while(r!=''):

r=f.read(1)

上述代码每次读取1个字节,一直读到空字符,说明到了文件末尾了。

使用f.readline()一行一行读取文件,每次读一行,循环读取直到读入的内容为空。演示代码如下:

r=f.readline()

while(r!=''):

r=f.readline()

无论f.read()、f.readline()、f.readlines(),默认都是从文件开头开始读起的。如果需要直接读取文件的某个位置的内容,那么就使用文件指针,从指针那里开始读起。使用f.seek()函数可以修改文件指针。

f.seek()有两个参数,第一个是位移,而第二个开始地点。开始地点有三种选择:

文件开头(os.SEEK_SET)

当前位置(os.SEEK_CUR)

文件结尾(os.SEEK_END)。

举几个例子:

f.seek(5,os.SEEK_SET)把指针指向文件开头顺数第五个字节;f.seek(-3,os.SEEK_END)把指针指向文件结尾倒数第三个字符。

修改了文件指针之后,文件的读写就会从当前的指针开始。

使用f.write()可以往文件里面添加内容。下面的例子展示了在文件末尾倒数一个字符的位置写入'5\n\'

with open(filename,'w') as f:

f.seek(-1,os.SEEK_END)

f.write('5\n')

文件内容的读写也涉及到了字符编码的问题,和之前提到的字符编码处理一样,需要按照编码类型decode成unicode字符,再进行处理;而写入的时候,把unicode字符encode为编码类型,再写入。

10.3 文件和目录的操作

python在os模块和os.path模块中提供了很多文件和目录的常用操作。

>>> import os.path

>>>os.path.exists('/Users/chenosanabin/Documents/dir0/dir1/file11.txt')

True

>>>os.path.isdir('/Users/chenosanabin/Documents/dir0/dir1/file11.txt')

False

>>>os.path.isfile('/Users/chenosanabin/Documents/dir0/dir1/file11.txt')

True

使用os.mkdir()或者os.makedirs()来创建目录

>>> os.path.exists('/Users/chenosanabin/Documents/d0')

False

>>>os.mkdir('/Users/chenosanabin/Documents/d0')

>>>os.path.exists('/Users/chenosanabin/Documents/d0')

True

当路径中有未创建的目录时,使用os.mkdir()进行创建会失败,这个时候应该使用os.makedirs()来循环创建目录

>>>os.mkdir('/Users/chenosanabin/Documents/d1/d11')

Traceback (most recent calllast):

File "", line 1, in

OSError: [Errno 2] No suchfile or directory: '/Users/chenosanabin/Documents/d1/d11'

>>>os.makedirs('/Users/chenosanabin/Documents/d1/d11')

>>> os.path.exists('/Users/chenosanabin/Documents/d1/d11')

True

使用os.rmdir()或者os.removedirs()来删除目录,此时需要删除的目录应该都是空的,如果不是空目录就不会被删除。

>>>os.rmdir('/Users/chenosanabin/Documents/d0')

>>>os.path.exists('/Users/chenosanabin/Documents/d0')

False

如果需要循环删除,可以使用os.removedirs(),只要文件路径的每个目录节点是空的,就进行删除。

>>>os.removedirs('/Users/chenosanabin/Documents/d1/d11')

>>>os.path.exists('/Users/chenosanabin/Documents/d1')

False

可以看到,在循环删除目录'/Users/chenosanabin/Documents/d1/d11'的时候,最终'/Users/chenosanabin/Documents/d1'也被删除了。

使用os.remove()来删除文件

>>>os.remove('/Users/chenosanabin/Documents/f1.txt')

>>>os.path.exists('/Users/chenosanabin/Documents/f1.txt')

False

使用os.walk()来遍历一个目录。

filelist=os.walk('/Users/chenosanabin/Documents/dir0')

for fl in filelist:

print(fl)

在这里'/Users/chenosanabin/Documents/dir0'是根目录,os.walk()从根目录开始遍历所有的子目录和子文件,并且把所有的目录下面的目录列表和文件列表列出来,结果用(root,dirlist,filelist)的形态展现。上述代码的输出类似于以下:

('/Users/chenosanabin/Documents/dir0',['dir1', 'dir2'], ['file1.txt'])

('/Users/chenosanabin/Documents/dir0/dir1',['dir11'], ['file11.txt'])

('/Users/chenosanabin/Documents/dir0/dir1/dir11',[], ['file111.txt'])

('/Users/chenosanabin/Documents/dir0/dir2',[], ['file21.txt'])

从结果可以看出,dir0目录下面有两个目录dir1和dir2,有一个文件file1.txt。而dir1目录下面有dir11目录和file11.txt文件。等等。

使用os.walk()可以很快地遍历一个根目录,访问所有的文件和目录,非常方便。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180614G21YWM00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券