文章内容
2017/9/22 10:51:42,作 者: 黄兵
Python 文件操作 永久存储(二)
2 文件系统:介绍一个高大上的东西
下面开始介绍一些Python的文件相关的模块。模块是什么?,模块就是Python源代码中的一个个(*.py)文件,在Python中有很多这样的模块,如果学会在使用的时候能够事半功倍。
在第一节的时候说过一个猜数字的游戏,里面就用到了random模块的randin()函数来生成随机数。然而在使用这些函数的时候不可以直接调用:
>>> random.randint(0,9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined
正确的用法应该是先导入模块,用import导入,后面加模块:
>>> import random
>>> random.randint(0,9)
7
>>> random.randint(0,9)
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() 函数就是获取当前目录:
>>> import os
>>> os.getcwd()
'/root'
#切换一下目录
[root@localhost games]# pwd
/usr/local/games
[root@localhost games]# python
Python 3.5.3 (default, Jul 8 2017, 13:46:38)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.getcwd()
'/usr/local/games' #目录和上面的pwd是一样的
2.2 chdir(path)
用chdir()函数就是改变当前的目录:
>>> import os
>>> path = '/root'
>>> os.getcwd()
'/usr/local/games'
>>> os.chdir(path)
>>> os.getcwd()
'/root'
>>> os.chdir('/usr/local/games/')
>>> os.getcwd()
'/usr/local/games'
2.3 listdir(path='.')
listdir(path='.')查看当前目录下的文件和子目录,默认值是‘.’,代表根目录,也可以使用‘..’代表上级目录
>>> import os
>>> os.chdir('/usr/local/games')
>>> os.listdir(path='.')
[]
>>> os.listdir(path='..')
['bin', 'etc', 'games', 'include', 'lib', 'lib64', 'libexec', 'sbin', 'share', 'src', 'python3']
2.4 mkdir(path)
mkdir()函数用于创建文件夹,如果该文件存在,则抛出异常FileExistsError:
>>> import os
>>> os.chdir('/usr/local/games')
>>> os.listdir(path='.')
[]
>>> os.mkdir('Python3v')
>>> os.listdir(path='.')
['Python3v']
>>> os.mkdir('Python3v')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileExistsError: [Errno 17] File exists: 'Python3v'
2.5 makedirs(path)
makedirs()函数是可以创建多层目录:
>>> import os
>>> os.listdir(path='.')
['Python3v']
>>> os.makedirs('a/b/c/d')
>>> os.listdir(path='.')
['Python3v', 'a']
>>> os.getcwd()
'/usr/local/games'
[root@localhost games]# tree a
a
└── b
└── c
└── d
如果是window环境需要加个转换符,这个在后面会讲,这里所有的操作都是用linux环境,毕竟写出来的程序要在linux环境中使用。
2.6 remove(path)、rmdir(path)和removedirs(path)
remove()函数用于删除指定的文件,注意是删除文件,不是删除目录。如果删除目录,则用rmdir()函数;如果要删除多层目录,则用removedirs()函数。
>>> import os
>>> os.listdir(path='.')
['Python3v', 'a', 'test.txt'] #用touch创建了一个test.txt
>>> os.remove('test.txt')
>>> os.listdir(path='.')
['Python3v', 'a']
>>> os.rmdir('Python3v')
>>> os.listdir(path='.')
['a']
>>> os.removedirs('a/b/c/d')
>>> os.listdir(path='.')
[]
2.7 rename(old,new)
rename()函数是用于重命名文件或者文件夹:
>>> import os
>>> os.mkdir('Python3v')
>>> os.listdir(path='.')
['Python3v', 'test.txt']
>>> os.rename('test.txt','Python')
>>> os.rename('Python3v','python')
>>> os.listdir(path='.')
['Python', 'python']
2.8 system(command)
system()函数是用于调用系统的命令
>>> import os
>>> os.listdir(path='.')
['Python', 'python']
>>> os.system('mkdir -p a/b/c/d')
0
>>> os.listdir(path='.')
['Python', 'python', 'a']
#在linux系统查看创建的文件
[root@localhost games]# tree a
a
└── b
└── c
└── d
2.9 walk(top)
walk()函数是遍历top参数指定路径下的所有子目录,并将结果返回一个三元组(路径,[包含目录],[包含文件])。看下面的例子:
>>> for i in os.walk('a'): #这个a是上面创建的多层目录
... print(i)
...
('a', ['b'], [])
('a/b', ['c'], [])
('a/b/c', ['d'], [])
('a/b/c/d', [], [])
为了方便理解,看一下文件的树结构:
[root@localhost games]# tree a
a
└── b
└── c
└── 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)函数分别用于获得文件名和路径名:
#先在多层目录下创建了一个文件
[root@localhost games]# tree a
a
└── b
└── c
└── d
└── abcd.txt
>>> import os
>>> os.getcwd()
'/usr/local/games'
>>> os.path.dirname('a/b/c/d/abcd.txt')
'a/b/c/d'
>>> os.path.basename('a/b/c/d/abcd.txt')
'abcd.txt'
2.11 join(path1[,path2[,...]])
join()函数跟BIF的那个join()函数不同,os.path.join()是用于将路径名和文件名组成一个完整的路径:
>>> import os
>>> os.getcwd()
'/usr/local/games'
>>> os.listdir()
['Python', 'python', 'a']
>>> os.path.join('/usr/local/games/a/b/c/d', 'abcd.txt')
'/usr/local/games/a/b/c/d/abcd.txt'
前面只是证明文件以及路径,可以直接使用os.path.join()函数调用,但是要导入OS。
2.12 split(path)和splitext(path)
split()和splitext()函数都用于分隔路径,split()函数分隔路径和文件名(如果完全使用目录,它也会将最后一个目录作为文件名分离,且不会判断文件或目录是否存在);splitext()函数则是用于分隔文件名和扩展名:
>>> import os
>>> os.path.split('/usr/local/games/a/b/c/d/abcd.txt')
('/usr/local/games/a/b/c/d', 'abcd.txt')
>>> os.path.splitext('/usr/local/games/a/b/c/d/abcd.txt')
('/usr/local/games/a/b/c/d/abcd', '.txt')
2.13 getsize(file)
getsize()函数用于获取文件的尺寸,返回值是以字节为单位:
我拷贝一个文件在/usr/local/games/目录下,先看看文件的大小然后在举例:
[root@localhost games]# ll
总用量 1172
drwxr-xr-x. 3 root root 14 7月 17 02:42 a
-rw-r--r--. 1 root root 1197370 11月 7 2016 pip-9.0.1.tar.gz
drwxr-xr-x. 2 root root 6 7月 17 02:37 python
-rw-r--r--. 1 root root 0 7月 17 02:37 Python
[root@localhost games]# python
Python 3.5.3 (default, Jul 8 2017, 13:46:38)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.path.getsize('pip-9.0.1.tar.gz')
1197370
2.14 getatime(file)、getctime(file)和getmtime(file)
getatime(file)、getctime()、getmtime()分别用于获得文件的最近访问时间,创建时间和修改时间。不过返回值是浮点型秒数,可用time模块的gmtime()或localtime()函数换算。
[root@localhost games]# ll
总用量 1216
drwxr-xr-x. 3 root root 14 7月 17 02:42 a
-rw-r--r--. 1 root root 1197370 11月 7 2016 pip-9.0.1.tar.gz
-rw-r--r--. 1 root root 43865 7月 8 13:44 pyconfig.h
drwxr-xr-x. 2 root root 6 7月 17 02:37 python
-rw-r--r--. 1 root root 0 7月 17 02:37 Python
[root@localhost games]# python
Python 3.5.3 (default, Jul 8 2017, 13:46:38)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> import time
>>> temp = time.localtime(os.path.getatime('pyconfig.h'))
>>> print('pyconfig.h被访问的时间是:', time.strftime('%d %b %Y %H:%M%S', temp))
pyconfig.h被访问的时间是: 08 Jul 2017 13:4500
>>> temp = time.localtime(os.path.getctime('pyconfig.h'))
>>> print('pyconfig.h被创建的时间是:', time.strftime('%d %b %Y %H: %M: %S', temp))
pyconfig.h被创建的时间是: 17 Jul 2017 05: 31: 19
>>> temp = time.localtime(os.path.getmtime('pyconfig.h'))
>>> print('pyconfig.h 被修改的时间是:', time.strftime('%d %b %Y %H: %M: %S', temp))
pyconfig.h 被修改的时间是: 08 Jul 2017 13: 44: 54
3 pickle:腌制一缸美味的泡菜
从一个文件里读取字符串非常简单,但是如果想要读取数值,无论是使用read()方法,还是使用readline()方法,都是返回一个字符串。除非是用int()函数或者float()函数把类似‘123’或‘3.14’这类字符串强制转换成具体的数值。
此前一直在说保存稳步,然而当要保存的数据像列表,字典甚至是泪点实例这些更复杂的数据类型时,普通的文件操作就会更变得不知所措。也许你会把这些都转换成为字符串,在写入一个文本文件中保存起来,但是很快你就会发现要把这个过程反过来,从文本文件恢复数据对象,就变的异常的麻烦。
这就是下面要说的pickle,Python提供pickle模块可以轻易的将列表、字典这类复杂的数据类型存储为文件里。pickle就是泡菜的意思,是把所有Python的对象都转化为二进制的形式存放,这个过程称为pickling,那么从二进制转换回对象的过程称为unpickling,看下面的例子:
[root@localhost games]# vi pi.py
import pickle
my_list = [123,3.14,'Python3v',['Hello Word']]
pickle_file = open('/usr/local/games/my_list.pkl', 'wb')
pickle.dump(my_list, pickle_file)
pickle_file.close()
[root@localhost games]# chmod +x pi.py
[root@localhost games]# python pi.py
[root@localhost games]# vi my_list.pkl
<80>^C]q^@(K{G@ ^^¸Që<85>^_X^H^@^@^@Python3vq^A]q^BX
^@^@^@Hello Wordq^Cae.
这里希望把列表永久保存起来(保存成文件),打开的文件一定要以二进制的形式打开,后缀名可以随意,不过既然用pickle保存,为了以后记忆,建议用.pkl或.pickle。使用dump方法来保存数据,完成后记得保存,跟操作普通文件一样。
程序执行后打开生成的my_list.pkl文件是一个乱码,因为这是二进制文件,只能用二进制方法打开,然后用load把数据加载进来:
[root@localhost games]# vi pi_read.py
import pickle
pickle_file = open('/usr/local/games/my_list.pkl', 'rb')
my_list = pickle.load(pickle_file)
print(my_list)
pickle_file.close()
[root@localhost games]# chmod +x pi_read.py
[root@localhost games]# python pi_read.py
[123, 3.14, 'Python3v', ['Hello Word']]
程序执行后又取回列表了,利用pickle模块,不仅可以保存列表,事实上pickle也可以保存任何你想像的任何东西。
4 文件发力
前面在说到open函数的时候使用的方法:
>>> f = open('read.txt', 'r+')
>>> f.read()
'这是追加的数据\n这是追加的数据'
>>> f.close()
把文件成功打开,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示,最后是调用close()方法关闭文件。如果文件在读的时候就出现异常不能关闭文件。所以为了保正文件能正确的关闭文件,可以使用try...finally实现:
try:
f = open('/path/to/file', 'r')
print(f.read())
finally:
if f:
f.close()
但是每次这么写是在太麻烦,所以Python引用了with语句自动帮助我们调用close()方法:
with open('/path/to/file', 'r') as f:
print(f.read())
这个和try...finally是一样的,代码更简洁,并且不必调用f.close()方法。
评论列表