文章内容

2017/9/22 10:51:42,作 者: 黄兵

Python 文件操作 永久存储(二)

2 文件系统:介绍一个高大上的东西

下面开始介绍一些Python的文件相关的模块。模块是什么?,模块就是Python源代码中的一个个(*.py)文件,在Python中有很多这样的模块,如果学会在使用的时候能够事半功倍。

在第一节的时候说过一个猜数字的游戏,里面就用到了random模块的randin()函数来生成随机数。然而在使用这些函数的时候不可以直接调用:

  1. >>> random.randint(0,9)

  2. Traceback (most recent call last):

  3.  File "<stdin>", line 1, in <module>

  4. NameError: name 'random' is not defined

正确的用法应该是先导入模块,用import导入,后面加模块:

  1. >>> import random

  2. >>> random.randint(0,9)

  3. 7

  4. >>> random.randint(0,9)

  5. 8

这里简单的说一点,如果导入的模块是自己写的,并且不在一个目录下,需要用到from后面跟目录,然后在是模块,在目录下必须自己手动创建一个int.py文件。后面在写项目的时候会详细说到,这里先简单说到这。

这里介绍的高大上的模块就是OS模块,OS就是Operating System的缩写,意思就是操作系统。之所以说OS是高大上的,是因为OS模块针对不同的操作系统,不需要修改代码,直接可以使用。OS模块可以帮你选择正确的模块并调用,不需要修改就能实现的。

这里列举了一下Os模块中关于文件/目录常用的函数使用方法

函数名 使用方法
getcwd() 返回当前工作目录
chdir(path) 改变工作目录
listdir(path='.') 列举指定目录中的文件名('.'表示当前目录,'..'表示上一级目录)
mkdir(path) 创建单层目录,如该目录已存在抛出异常
makedirs(path) 递归创建多层目录,如果目录已存在则抛出异常,注意:'C:\a\b'和'C:\a\c'并不冲突
remove(path) 删除文件
rmdir(path) 删除单层目录,如果该目录非空则抛出异常
removedirs(path) 递归删除目录,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常
rename(old,new) 将文件old重命名new
system(command) 运行系统的shell命令
os.curdir 指代当前目录('.')
os.pardir 指代上一级目录(‘..’)
os.sep 输出操作系统特定的路径分隔符(在Windows下为'\',Linux下为'/')
os.linesep 当前平台使用的行终止符(在Windows下为‘\r\n’,Linux下为'\n')
os.name 指代当前使用的操作系统(包括‘posix’、‘nt’、‘mac’、‘os2’、‘ce’、‘java’)

2.1 getcwd()函数

getcwd() 函数就是获取当前目录:

  1. >>> import os

  2. >>> os.getcwd()

  3. '/root'

  4. #切换一下目录

  5. [root@localhost games]# pwd

  6. /usr/local/games

  7. [root@localhost games]# python

  8. Python 3.5.3 (default, Jul  8 2017, 13:46:38)

  9. [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux

  10. Type "help", "copyright", "credits" or "license" for more information.

  11. >>> import os

  12. >>> os.getcwd()

  13. '/usr/local/games'  #目录和上面的pwd是一样的

2.2 chdir(path)

用chdir()函数就是改变当前的目录:

  1. >>> import os                    

  2. >>> path = '/root'              

  3. >>> os.getcwd()                  

  4. '/usr/local/games'

  5. >>> os.chdir(path)              

  6. >>> os.getcwd()  

  7. '/root'

  8. >>> os.chdir('/usr/local/games/')

  9. >>> os.getcwd()

  10. '/usr/local/games'

2.3 listdir(path='.')

listdir(path='.')查看当前目录下的文件和子目录,默认值是‘.’,代表根目录,也可以使用‘..’代表上级目录

  1. >>> import os

  2. >>> os.chdir('/usr/local/games')

  3. >>> os.listdir(path='.')

  4. []

  5. >>> os.listdir(path='..')

  6. ['bin', 'etc', 'games', 'include', 'lib', 'lib64', 'libexec', 'sbin', 'share', 'src', 'python3']

2.4 mkdir(path)

mkdir()函数用于创建文件夹,如果该文件存在,则抛出异常FileExistsError:

  1. >>> import os

  2. >>> os.chdir('/usr/local/games')

  3. >>> os.listdir(path='.')

  4. []

  5. >>> os.mkdir('Python3v')

  6. >>> os.listdir(path='.')

  7. ['Python3v']

  8. >>> os.mkdir('Python3v')

  9. Traceback (most recent call last):

  10.  File "<stdin>", line 1, in <module>

  11. FileExistsError: [Errno 17] File exists: 'Python3v'

2.5 makedirs(path)

makedirs()函数是可以创建多层目录:

  1. >>> import os

  2. >>> os.listdir(path='.')

  3. ['Python3v']

  4. >>> os.makedirs('a/b/c/d')

  5. >>> os.listdir(path='.')  

  6. ['Python3v', 'a']

  7. >>> os.getcwd()

  8. '/usr/local/games'

  9. [root@localhost games]# tree a

  10. a

  11. └── b

  12.    └── c

  13.        └── d

如果是window环境需要加个转换符,这个在后面会讲,这里所有的操作都是用linux环境,毕竟写出来的程序要在linux环境中使用。

2.6 remove(path)、rmdir(path)和removedirs(path)

remove()函数用于删除指定的文件,注意是删除文件,不是删除目录。如果删除目录,则用rmdir()函数;如果要删除多层目录,则用removedirs()函数。

  1. >>> import os            

  2. >>> os.listdir(path='.')

  3. ['Python3v', 'a', 'test.txt']   #用touch创建了一个test.txt

  4. >>> os.remove('test.txt')

  5. >>> os.listdir(path='.')

  6. ['Python3v', 'a']

  7. >>> os.rmdir('Python3v')

  8. >>> os.listdir(path='.')

  9. ['a']

  10. >>> os.removedirs('a/b/c/d')

  11. >>> os.listdir(path='.')    

  12. []

2.7 rename(old,new)

rename()函数是用于重命名文件或者文件夹:

  1. >>> import os

  2. >>> os.mkdir('Python3v')

  3. >>> os.listdir(path='.')

  4. ['Python3v', 'test.txt']

  5. >>> os.rename('test.txt','Python')

  6. >>> os.rename('Python3v','python')

  7. >>> os.listdir(path='.')          

  8. ['Python', 'python']

2.8 system(command)

system()函数是用于调用系统的命令

  1. >>> import os

  2. >>> os.listdir(path='.')

  3. ['Python', 'python']

  4. >>> os.system('mkdir -p a/b/c/d')

  5. 0

  6. >>> os.listdir(path='.')        

  7. ['Python', 'python', 'a']

  8. #在linux系统查看创建的文件

  9. [root@localhost games]# tree a

  10. a

  11. └── b

  12.    └── c

  13.        └── d

2.9 walk(top)

walk()函数是遍历top参数指定路径下的所有子目录,并将结果返回一个三元组(路径,[包含目录],[包含文件])。看下面的例子:

  1. >>> for i in os.walk('a'):  #这个a是上面创建的多层目录

  2. ...     print(i)

  3. ...

  4. ('a', ['b'], [])

  5. ('a/b', ['c'], [])

  6. ('a/b/c', ['d'], [])

  7. ('a/b/c/d', [], [])

为了方便理解,看一下文件的树结构:

  1. [root@localhost games]# tree a

  2. a

  3. └── b

  4.    └── c

  5.        └── d

另外path模块还提供了一些实用的定义,分别是:os.curdir表示当前目录;so.pardir表示上级目录('..');os.sep表示路径的分隔符,比如window系统下的'\',linux下为‘/’;os.linesep表示当前平台使用的行终止符(在Windows下为'\r\n',linux下为'\n');os.name表示当前使用的操作系统。

另一个强大的模块就是os.path,它可以完成一些针对路径名的操作,下面列举了一些,os.path中常用到的函数使用方法:

函数名 使用方法
basename(path) 去掉目录路径,单独返回文件名
dirname(path) 去掉文件名,单独返回目录路径
join(path1[,path2[,...]]) 将path1和path2各部分组合成一个路径名
split(path) 分割文件名与路径,返回(fpath,fname)元组,如果完全使用目录,它也会将最后一个目录作为文件名分离,且不会判断文件或者目录是否存在
splitext(path) 分离文件名与扩展名,返回(fname,fextension)元组
getsize(file) 返回指定文件的尺寸,单位是字节
getatime(file) 返回指定文件最近的访问时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算
getctime(file) 返回指定文件的创建时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
getmtime(file) 返回指定文件最新的修改时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
exists(path) 判断指定路径(目录或文件)是否存在
isabs(path) 判断指定路径是否为绝对路径
isdir(path) 判断指定路径是否存在且是一个目录
isfile(path) 判断指定路径是否存在且是一个文件
islink(path) 判断指定路径是否存在且是一个符号链接
ismount(path) 判断指定路径是否存在且是一个挂载点
samefile(path1,path2) 判断path1和path2两个路径是否指向同一个文件

2.10 basename(path)和dirname(path)

basename()和dirname(path)函数分别用于获得文件名和路径名:

  1. #先在多层目录下创建了一个文件

  2. [root@localhost games]# tree a

  3. a

  4. └── b

  5.    └── c

  6.        └── d

  7.            └── abcd.txt

  8. >>> import os

  9. >>> os.getcwd()

  10. '/usr/local/games'

  11. >>> os.path.dirname('a/b/c/d/abcd.txt')

  12. 'a/b/c/d'

  13. >>> os.path.basename('a/b/c/d/abcd.txt')

  14. 'abcd.txt'

2.11 join(path1[,path2[,...]])

join()函数跟BIF的那个join()函数不同,os.path.join()是用于将路径名和文件名组成一个完整的路径:

  1. >>> import os

  2. >>> os.getcwd()

  3. '/usr/local/games'

  4. >>> os.listdir()

  5. ['Python', 'python', 'a']

  6. >>> os.path.join('/usr/local/games/a/b/c/d', 'abcd.txt')

  7. '/usr/local/games/a/b/c/d/abcd.txt'

前面只是证明文件以及路径,可以直接使用os.path.join()函数调用,但是要导入OS。

2.12 split(path)和splitext(path)

split()和splitext()函数都用于分隔路径,split()函数分隔路径和文件名(如果完全使用目录,它也会将最后一个目录作为文件名分离,且不会判断文件或目录是否存在);splitext()函数则是用于分隔文件名和扩展名:

  1. >>> import os

  2. >>> os.path.split('/usr/local/games/a/b/c/d/abcd.txt')

  3. ('/usr/local/games/a/b/c/d', 'abcd.txt')

  4. >>> os.path.splitext('/usr/local/games/a/b/c/d/abcd.txt')

  5. ('/usr/local/games/a/b/c/d/abcd', '.txt')

2.13 getsize(file)

getsize()函数用于获取文件的尺寸,返回值是以字节为单位:

我拷贝一个文件在/usr/local/games/目录下,先看看文件的大小然后在举例:

  1. [root@localhost games]# ll

  2. 总用量 1172

  3. drwxr-xr-x. 3 root root      14 7  17 02:42 a

  4. -rw-r--r--. 1 root root 1197370 11  7 2016 pip-9.0.1.tar.gz

  5. drwxr-xr-x. 2 root root       6 7  17 02:37 python

  6. -rw-r--r--. 1 root root       0 7  17 02:37 Python

  7. [root@localhost games]# python

  8. Python 3.5.3 (default, Jul  8 2017, 13:46:38)

  9. [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux

  10. Type "help", "copyright", "credits" or "license" for more information.

  11. >>> import os

  12. >>> os.path.getsize('pip-9.0.1.tar.gz')

  13. 1197370

2.14 getatime(file)、getctime(file)和getmtime(file)

getatime(file)、getctime()、getmtime()分别用于获得文件的最近访问时间,创建时间和修改时间。不过返回值是浮点型秒数,可用time模块的gmtime()或localtime()函数换算。

  1. [root@localhost games]# ll

  2. 总用量 1216

  3. drwxr-xr-x. 3 root root      14 7  17 02:42 a

  4. -rw-r--r--. 1 root root 1197370 11  7 2016     pip-9.0.1.tar.gz

  5. -rw-r--r--. 1 root root   43865 7   8 13:44 pyconfig.h

  6. drwxr-xr-x. 2 root root       6 7  17 02:37 python

  7. -rw-r--r--. 1 root root       0 7  17 02:37 Python

  8. [root@localhost games]# python

  9. Python 3.5.3 (default, Jul  8 2017, 13:46:38)

  10. [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux

  11. Type "help", "copyright", "credits" or "license" for more information.

  12. >>> import os

  13. >>> import time

  14. >>> temp = time.localtime(os.path.getatime('pyconfig.h'))

  15. >>> print('pyconfig.h被访问的时间是:', time.strftime('%d %b %Y %H:%M%S', temp))

  16. pyconfig.h被访问的时间是: 08 Jul 2017 13:4500

  17. >>> temp = time.localtime(os.path.getctime('pyconfig.h'))

  18. >>> print('pyconfig.h被创建的时间是:', time.strftime('%d %b %Y %H: %M: %S', temp))

  19. pyconfig.h被创建的时间是: 17 Jul 2017 05: 31: 19

  20. >>> temp = time.localtime(os.path.getmtime('pyconfig.h'))

  21. >>> print('pyconfig.h 被修改的时间是:', time.strftime('%d %b %Y %H: %M: %S', temp))

  22. pyconfig.h 被修改的时间是: 08 Jul 2017 13: 44: 54

3 pickle:腌制一缸美味的泡菜

从一个文件里读取字符串非常简单,但是如果想要读取数值,无论是使用read()方法,还是使用readline()方法,都是返回一个字符串。除非是用int()函数或者float()函数把类似‘123’或‘3.14’这类字符串强制转换成具体的数值。

此前一直在说保存稳步,然而当要保存的数据像列表,字典甚至是泪点实例这些更复杂的数据类型时,普通的文件操作就会更变得不知所措。也许你会把这些都转换成为字符串,在写入一个文本文件中保存起来,但是很快你就会发现要把这个过程反过来,从文本文件恢复数据对象,就变的异常的麻烦。

这就是下面要说的pickle,Python提供pickle模块可以轻易的将列表、字典这类复杂的数据类型存储为文件里。pickle就是泡菜的意思,是把所有Python的对象都转化为二进制的形式存放,这个过程称为pickling,那么从二进制转换回对象的过程称为unpickling,看下面的例子:

  1. [root@localhost games]# vi pi.py

  2. import pickle

  3. my_list = [123,3.14,'Python3v',['Hello Word']]

  4. pickle_file = open('/usr/local/games/my_list.pkl', 'wb')

  5. pickle.dump(my_list, pickle_file)

  6. pickle_file.close()

  7. [root@localhost games]# chmod +x pi.py

  8. [root@localhost games]# python pi.py

  9. [root@localhost games]# vi my_list.pkl

  10. <80>^C]q^@(K{G@ ^^¸Që<85>^_X^H^@^@^@Python3vq^A]q^BX

  11. ^@^@^@Hello Wordq^Cae.

这里希望把列表永久保存起来(保存成文件),打开的文件一定要以二进制的形式打开,后缀名可以随意,不过既然用pickle保存,为了以后记忆,建议用.pkl或.pickle。使用dump方法来保存数据,完成后记得保存,跟操作普通文件一样。

程序执行后打开生成的my_list.pkl文件是一个乱码,因为这是二进制文件,只能用二进制方法打开,然后用load把数据加载进来:

  1. [root@localhost games]# vi pi_read.py

  2. import pickle

  3. pickle_file = open('/usr/local/games/my_list.pkl', 'rb')

  4. my_list = pickle.load(pickle_file)

  5. print(my_list)

  6. pickle_file.close()

  7. [root@localhost games]# chmod +x pi_read.py

  8. [root@localhost games]# python pi_read.py

  9. [123, 3.14, 'Python3v', ['Hello Word']]

程序执行后又取回列表了,利用pickle模块,不仅可以保存列表,事实上pickle也可以保存任何你想像的任何东西。

4 文件发力

前面在说到open函数的时候使用的方法:

  1. >>> f = open('read.txt', 'r+')

  2. >>> f.read()

  3. '这是追加的数据\n这是追加的数据'

  4. >>> f.close()

把文件成功打开,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示,最后是调用close()方法关闭文件。如果文件在读的时候就出现异常不能关闭文件。所以为了保正文件能正确的关闭文件,可以使用try...finally实现:

  1. try:

  2.    f = open('/path/to/file', 'r')

  3.    print(f.read())

  4. finally:

  5.    if f:

  6.        f.close()

但是每次这么写是在太麻烦,所以Python引用了with语句自动帮助我们调用close()方法:

  1. with open('/path/to/file', 'r') as f:

  2.    print(f.read())

这个和try...finally是一样的,代码更简洁,并且不必调用f.close()方法。

分享到:

发表评论

评论列表