标准库 (3)

OS

os 模块提供了访问操作系统服务的功能,它所包含的内容比较多。

>>> import os
>>> dir(os)
['EX_CANTCREAT', 'EX_CONFIG', 'EX_DATAERR', 'EX_IOERR', 'EX_NOHOST', 'EX_NOINPUT', 'EX_NOPERM', 'EX_NOUSER','EX_OK', 'EX_OSERR', 'EX_OSFILE', 'EX_PROTOCOL', 'EX_SOFTWARE', 'EX_TEMPFAIL', 'EX_UNAVAILABLE', 'EX_USAGE', 'F_OK', 'NGROUPS_MAX', 'O_APPEND', 'O_ASYNC', 'O_CREAT', 'O_DIRECT', 'O_DIRECTORY', 'O_DSYNC', 'O_EXCL', 'O_LARGEFILE', 'O_NDELAY', 'O_NOATIME', 'O_NOCTTY', 'O_NOFOLLOW', 'O_NONBLOCK', 'O_RDONLY', 'O_RDWR', 'O_RSYNC', 'O_SYNC', 'O_TRUNC', 'O_WRONLY', 'P_NOWAIT', 'P_NOWAITO', 'P_WAIT', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'ST_APPEND', 'ST_MANDLOCK', 'ST_NOATIME', 'ST_NODEV', 'ST_NODIRATIME', 'ST_NOEXEC', 'ST_NOSUID', 'ST_RDONLY', 'ST_RELATIME', 'ST_SYNCHRONOUS', 'ST_WRITE', 'TMP_MAX', 'UserDict', 'WCONTINUED', 'WCOREDUMP', 'WEXITSTATUS', 'WIFCONTINUED', 'WIFEXITED', 'WIFSIGNALED', 'WIFSTOPPED', 'WNOHANG', 'WSTOPSIG', 'WTERMSIG', 'WUNTRACED', 'W_OK', 'X_OK', '_Environ', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_copy_reg', '_execvpe', '_exists', '_exit', '_get_exports_list', '_make_stat_result', '_make_statvfs_result', '_pickle_stat_result', '_pickle_statvfs_result', '_spawnvef', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'chown', 'chroot', 'close', 'closerange', 'confstr', 'confstr_names', 'ctermid', 'curdir', 'defpath', 'devnull', 'dup', 'dup2', 'environ', 'errno', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fchdir', 'fchmod', 'fchown', 'fdatasync', 'fdopen', 'fork', 'forkpty', 'fpathconf', 'fstat', 'fstatvfs', 'fsync', 'ftruncate', 'getcwd', 'getcwdu', 'getegid', 'getenv', 'geteuid', 'getgid', 'getgroups', 'getloadavg', 'getlogin', 'getpgid', 'getpgrp', 'getpid', 'getppid', 'getresgid', 'getresuid', 'getsid', 'getuid', 'initgroups', 'isatty', 'kill', 'killpg', 'lchown', 'linesep', 'link', 'listdir', 'lseek', 'lstat', 'major', 'makedev', 'makedirs', 'minor', 'mkdir', 'mkfifo', 'mknod', 'name', 'nice', 'open', 'openpty', 'pardir', 'path', 'pathconf', 'pathconf_names', 'pathsep', 'pipe', 'popen', 'popen2', 'popen3', 'popen4', 'putenv', 'read', 'readlink', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'sep', 'setegid', 'seteuid', 'setgid', 'setgroups', 'setpgid', 'setpgrp', 'setregid', 'setresgid', 'setresuid', 'setreuid', 'setsid', 'setuid', 'spawnl', 'spawnle', 'spawnlp', 'spawnlpe', 'spawnv', 'spawnve', 'spawnvp', 'spawnvpe', 'stat', 'stat_float_times', 'stat_result', 'statvfs', 'statvfs_result', 'strerror', 'symlink', 'sys', 'sysconf', 'sysconf_names', 'system', 'tcgetpgrp', 'tcsetpgrp', 'tempnam', 'times', 'tmpfile', 'tmpnam', 'ttyname', 'umask', 'uname', 'unlink', 'unsetenv', 'urandom', 'utime', 'wait', 'wait3', 'wait4', 'waitpid', 'walk', 'write']

这么多内容不能都介绍,况且不少方法在实践中用的不多,比如 os.popen() 在实践中用到了,但是 os 模块还有 popen2、popen3、popen4,这三个我在实践中都没有用过,或者有别人用了,也请补充。不过,我下面介绍的都是自认为用的比较多的,至少是我用的比较多或者用过的。如果没有读者要是用,但是我这里没有介绍,读者也完全可以自己用我们常用的 help() 来自学明白其应用方法,当然,还有最好的工具------google(内事不决问 google,外事不明问谷歌,须梯子)。

操作文件:重命名、删除文件

在对文件操作的时候,open() 这个内建函数可以建立、打开文件。但是,如果对文件进行改名、删除操作,就要是用 os 模块的方法了。

首先建立一个文件,文件名为 22201.py,文件内容是:

#!/usr/bin/env python
# coding=utf-8

print "This is a tmp file."

然后将这个文件名称修改为其它的名称。

>>> import os
>>> os.rename("22201.py", "newtemp.py")

注意,我是先进入到了文件 22201.py 的目录,然后进入到 Python 交互模式,所以,可以直接写文件名,如果不是这样,需要将文件名的路径写上。os.rename("22201.py", "newtemp.py")中,第一个文件是原文件名称,第二个是打算修改成为的文件名。

$ ls new*
newtemp.py

查看,能够看到这个文件。并且文件内容可以用 cat newtemp.py 看看(这是在 ubuntu 系统,如果是 windows 系统,可以用其相应的编辑器打开文件看内容)。

Help on built-in function rename in module posix:

rename(...)
    rename(old, new)

    Rename a file or directory.

除了修改文件名称,还可以修改目录名称。请注意阅读帮助信息。

另外一个 os.remove(),首先看帮助信息,然后再实验。

Help on built-in function remove in module posix:

remove(...)
    remove(path)

    Remove a file (same as unlink(path)).

比较简单。那就测试一下。为了测试,先建立一些文件吧。

$ pwd
/home/qw/Documents/VBS/StarterLearningPython/2code/rd

这是我建立的临时目录,里面有几个文件:

$ ls
a.py  b.py  c.py

下面删除 a.py 文件

>>> import os
>>> os.remove("/home/qw/Documents/VBS/StarterLearningPython/2code/rd/a.py")

看看删了吗?

$ ls
b.py  c.py

果然管用呀。再来一个狠的:

>>> os.remove("/home/qw/Documents/VBS/StarterLearningPython/2code/rd")
Traceback (most recent call last): 
  File "<stdin>", line 1, in <module>
OSError: [Errno 21] Is a directory: '/home/qw/Documents/VBS/StarterLearningPython/2code/rd'

报错了。我打算将这个目录下的所剩文件删光光。这么做不行。注意帮助中一句话 Remove a file,os.remove() 就是用来删除文件的。并且从报错中也可以看到,告诉我们错误的原因在于那个参数是一个目录。

要删除目录,还得继续向下学习。

操作目录

os.listdir :显示目录中的文件

Help on built-in function listdir in module posix:

listdir(...)
    listdir(path) -> list_of_strings

Return a list containing the names of the entries in the directory.

    path: path of directory to list

The list is in arbitrary order.  It does not include the special
entries '.' and '..' even if they are present in the directory.

看完帮助信息,读者一定觉得这是一个非常简单的方法,不过,特别注意它返回的值是列表,还有就是如果文件夹中有那样的特殊格式命名的文件,不显示。在 linux 中,用 ls 命令也看不到这些隐藏的东东。

>>> os.listdir("/home/qw/Documents/VBS/StarterLearningPython/2code/rd")
['b.py', 'c.py']
>>> files = os.listdir("/home/qw/Documents/VBS/StarterLearningPython/2code/rd")
>>> for f in files:
...     print f
... 
b.py
c.py

os.getcwd, os.chdir :当前工作目录,改变当前工作目录

这两个函数怎么用?惟有通过 help() 看文档啦。请读者自行看看。我就不贴出来了,仅演示一个例子:

>>> cwd = os.getcwd()     #当前目录
>>> print cwd
/home/qw/Documents/VBS/StarterLearningPython/2code/rd
>>> os.chdir(os.pardir)    #进入到上一级

>>> os.getcwd()            #当前
'/home/qw/Documents/VBS/StarterLearningPython/2code'

>>> os.chdir("rd")         #进入下级

>>> os.getcwd()
'/home/qw/Documents/VBS/StarterLearningPython/2code/rd'

os.pardir 的功能是获得父级目录,相当于..

>>> os.pardir
'..'

os.makedirs, os.removedirs :创建和删除目录

废话少说,路子还是前面那样,就省略看帮助了,读者可以自己看。直接上例子:

>>> dir = os.getcwd()
>>> dir
'/home/qw/Documents/VBS/StarterLearningPython/2code/rd'
>>> os.removedirs(dir)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/os.py", line 170, in removedirs
    rmdir(name)
OSError: [Errno 39] Directory not empty: '/home/qw/Documents/VBS/StarterLearningPython/2code/rd'

什么时候都不能得意忘形,一定要谦卑。那就是从看文档开始一点一点地理解。不能像上面那样,自以为是、贸然行事。看报错信息,要删除某个目录,那个目录必须是空的。

>>> os.getcwd()                   
'/home/qw/Documents/VBS/StarterLearningPython/2code'

这是当前目录,在这个目录下再建一个新的子目录:

>>> os.makedirs("newrd")
>>> os.chdir("newrd")
>>> os.getcwd()
'/home/qw/Documents/VBS/StarterLearningPython/2code/newrd'

建立了一个。下面把这个删除了。这个是空的。

>>> os.listdir(os.getcwd())
[]
>>> newdir = os.getcwd()
>>> os.removedirs(newdir)

按照我的理解,这里应该报错。因为我是在当前工作目录删除当前工作目录。如果这样能够执行,总觉得有点别扭。但事实上,就行得通了。就算是 python 的规定吧。不过,让我来确定这个功能的话,还是习惯不能在本地删除本地。

按照上面的操作,在看当前工作目录:

>>> os.getcwd()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory

目录被删了,当然没有啦。只能回到父级。

>>> os.chdir(os.pardir)
>>> os.getcwd()
'/home/qw/Documents/VBS/StarterLearningPython/2code'

有点不可思议。本来没有当前工作目录,怎么会有"父级"的呢?但 Python 就是这样。

补充一点,前面说的如果目录不空,就不能用 os.removedirs() 删除。但是,可以用模块 shutil 的 retree 方法。

>>> os.getcwd()
'/home/qw/Documents/VBS/StarterLearningPython/2code'
>>> os.chdir("rd")
>>> now = os.getcwd()
>>> now
'/home/qw/Documents/VBS/StarterLearningPython/2code/rd'
>>> os.listdir(now)
['b.py', 'c.py']
>>> import shutil
>>> shutil.rmtree(now)
>>> os.getcwd()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory

请读者注意的是,对于 os.makedirs() 还有这样的特点:

>>> os.getcwd()
'/home/qw/Documents/VBS/StarterLearningPython/2code'
>>> d0 = os.getcwd()
>>> d1 = d0+"/ndir1/ndir2/ndir3"    #这是想建立的目录,但是中间的 ndir1,ndir2 也都不存在。
>>> d1
'/home/qw/Documents/VBS/StarterLearningPython/2code/ndir1/ndir2/ndir3'
>>> os.makedirs(d1)
>>> os.chdir(d1)
>>> os.getcwd()
'/home/qw/Documents/VBS/StarterLearningPython/2code/ndir1/ndir2/ndir3'

中间不存在的目录也被建立起来,直到做右边的目录为止。与 os.makedirs() 类似的还有 os.mkdir(),不过,os.mkdir() 没有上面这个功能,它只能一层一层地建目录。

os.removedirs()os.rmdir() 也类似,区别也类似上面。

文件和目录属性

不管是在什么操作系统,都能看到文件或者目录的有关属性,那么,在 os 模块中,也有这样的一个方法:os.stat()

>>> p = os.getcwd()    #当前目录
>>> p
'/home/qw/Documents/VBS/StarterLearningPython'

# 这个目录的有关信息
>>> os.stat(p)
posix.stat_result(st_mode=16895, st_ino=4L, st_dev=26L, st_nlink=1, st_uid=0, st_gid=0, st_size=12288L, st_atime=1430224935, st_mtime=1430224935, st_ctime=1430224935)

# 指定一个文件
>>> pf = p + "/index.html"
# 此文件的信息
>>> os.stat(pf)
posix.stat_result(st_mode=33279, st_ino=67L, st_dev=26L, st_nlink=1, st_uid=0, st_gid=0, st_size=50L, st_atime=1429580969, st_mtime=1429580969, st_ctime=1429580969)

从结果中看,可能看不出什么来,先不用着急。这样的结果是对 computer 姑娘友好的,对读者可能不友好。如果用下面的方法,就友好多了:

>>> fi = os.stat(pf)
>>> mt = fi[8]

fi[8] 就是 st_mtime 的值,它代表最后 modified(修改)文件的时间。看结果:

>>> mt
1429580969

还是不友好。下面就用 time 模块来友好一下:

>>> import time
>>> time.ctime(mt)
'Tue Apr 21 09:49:29 2015'

现在就对读者友好了。

os.stat() 能够查看文件或者目录的属性。如果要修改呢?比如在部署网站的时候,常常要修改目录或者文件的权限等。这种操作在 Python 的 os 模块能做到吗?

要求越来越多了。在一般情况下,不在 Python 里做这个呀。当然,世界是复杂的。肯定有人会用到的,所以 os 模块提供了 os.chmod()

操作命令

读者如果使用某种 linux 系统,或者曾经用过 dos(恐怕很少),或者再 windows 里面用过 command,对敲命令都不陌生。通过命令来做事情的确是很酷的。比如,我是在 ubuntu 中,要查看文件和目录,只需要 ls 就足够了。我并不是否认图形界面,而是在某些情况下,还是离不开命令的,比如用程序来完成查看文件和目录的操作。所以,os 模块中提供了这样的方法,许可程序员在 Python 程序中使用操作系统的命令。(以下是在 ubuntu 系统,如果读者是 windows,可以将命令换成 DOS 命令。)

>>> p
'/home/qw/Documents/VBS/StarterLearningPython'
>>> command = "ls " + p
>>> command
'ls /home/qw/Documents/VBS/StarterLearningPython'

为了输入方便,我采用了前面例子中已经有的那个目录,并且,用拼接字符串的方式,将要输入的命令(查看某文件夹下的内容)组装成一个字符串,赋值给变量 command,然后:

>>> os.system(command)
01.html    101.html  105.html  109.html  113.html  117.html  121.html  125.html  129.html   201.html  205.html  209.html  213.html  217.html  221.html   index.html
02.html    102.html  106.html  110.html  114.html  118.html  122.html  126.html  130.html   202.html  206.html  210.html  214.html  218.html  222.html   n001.html
03.html    103.html  107.html  111.html  115.html  119.html  123.html  127.html  1code    203.html  207.html  211.html  215.html  219.html  2code    index.html
0images  104.html  108.html  112.html  116.html  120.html  124.html  128.html  images  204.html  208.html  212.html  216.html  220.html  images
0

这样就列出来了该目录下的所有内容。

需要注意的是,os.system() 是在当前进程中执行命令,直到它执行结束。如果需要一个新的进程,可以使用 os.exec 或者 os.execvp。对此有兴趣详细了解的读者,可以查看帮助文档了解。另外,os.system() 是通过 shell 执行命令,执行结束后将控制权返回到原来的进程,但是 os.exec() 及相关的函数,则在执行后不将控制权返回到原继承,从而使 Python 失去控制。

关于 Python 对进程的管理,此处暂不过多介绍。

os.system() 是一个用途不少的函数。曾有一个朋友网上询问,用它来启动浏览器。不过,这个操作的确要非常仔细。为什么呢?演示一下就明白了。

>>> os.system("/usr/bin/firefox")

(process:4002): GLib-CRITICAL **: g_slice_set_config: assertion 'sys_page_size == 0' failed

(firefox:4002): GLib-GObject-WARNING **: Attempt to add property GnomeProgram::sm-connect after class was initialised
......

我是在 ubuntu 上操作的,浏览器的地址是 /usr/bin/firefox,可是,那个朋友是 windows,他就要非常小心了,因为在 windows 里面,表示路径的斜杠是跟上面显示的是反着的,可是在 Python 中 \\ 这种斜杠代表转义。解决这个问题可以参看《字符串(1)》的转义符以及《字符串(2)》的原始字符串讲述。比较简单的一个方法用 r"c:\\user\\firfox.exe" 的样式,因为在 r" " 中的,都是被认为原始字符了。还没完,因为 windows 系统中,一般情况下那个文件不是安装在我演示的那个简单样式的文件夹中,而是 C:\\Program Files,这中间还有空格,所以还要注意,空格问题。简直有点晕头转向了。读者按照这些提示,看看能不能完成用 os.system() 启动 firefox 的操作呢?

凡事感觉麻烦的东西,必然有另外简单的来替代。于是又有了一个 webbrowser 模块。可以专门用来打开指定网页。

>>> import webbrowser
>>> webbrowser.open("http://www.itdiffer.com")
True

不管是什么操作系统,只要如上操作就能打开网页了。

真是神奇的标准库,有如此多的工具,能不加速开发进程吗?能不降低开发成本吗?"人生苦短,我用 Python"!


总目录 | 上节:标准库(2) | 下节:标准库(4)

如果你认为有必要打赏我,请通过支付宝: qiwsir@126.com ,不胜感激。