你们要谨慎行事,不要像愚昧人,当像智慧人。要爱惜光阴,因为现今的世代邪恶。不要作糊涂人,要明白主的旨意如何。不要醉酒,酒能使人放荡,乃要被圣灵充满。(EPHESIANS 5:15-18)

标准库(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']

这么多内容不能都介绍,列出来纯粹是要吓唬你一下,先混个脸熟,将来用到哪个了,可以到这里来找。

下面选择几个介绍一番,目的是不断强化我已经常用但是不知道你是否熟悉的学习方法,当然,还有最好的工具——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的目录,然后进入交互模式,所以,可以直接写文件名,如果不是这样,需要将文件名的路径写上。

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.

看完帮助信息,读者一定觉得这是一个非常简单的方法,不过,特别注意它返回的值是列表,且不显示目录中某些隐藏文件或子目录。

>>> 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'

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

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

>>> 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 + "/README.md"

显示此文件的信息:

>>> 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.md     101.md  105.md  109.md  113.md  117.md  121.md  125.md  129.md   201.md  205.md  209.md  213.md  217.md  221.md   index.md
02.md     102.md  106.md  110.md  114.md  118.md  122.md  126.md  130.md   202.md  206.md  210.md  214.md  218.md  222.md   n001.md
03.md     103.md  107.md  111.md  115.md  119.md  123.md  127.md  1code      203.md  207.md  211.md  215.md  219.md  2code    README.md
0images  104.md  108.md  112.md  116.md  120.md  124.md  128.md  1images  204.md  208.md  212.md  216.md  220.md  2images
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中\代表转义。比较简单的一个方法是用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)

如果你认为有必要打赏我,请通过支付宝:[email protected],不胜感激。

results matching ""

    No results matching ""