|
| 1 | +>你们要谨慎行事,不要像愚昧人,当像智慧人。要爱惜光阴,因为现今的世代邪恶。不要作糊涂人,要明白主的旨意如何。不要醉酒,酒能使人放荡,乃要被圣灵充满。(EPHESIANS 4:15-18) |
| 2 | +
|
| 3 | +#标准库(3) |
| 4 | + |
| 5 | +##OS |
| 6 | + |
| 7 | +os模块提供了访问操作系统服务的功能,它所包含的内容比较多。 |
| 8 | + |
| 9 | + >>> import os |
| 10 | + >>> dir(os) |
| 11 | + ['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'] |
| 12 | + |
| 13 | +这么多内容不能都介绍,况且不少方法在实践中用的不多,比如`os.popen()`在实践中用到了,但是os模块还有popen2、popen3、popen4,这三个我在实践中都没有用过,或者有别人用了,也请补充。不过,我下面介绍的都是自认为用的比较多的,至少是我用的比较多或者用过的。如果没有读者要是用,但是我这里没有介绍,读者也完全可以自己用我们常用的`help()`来自学明白其应用方法,当然,还有最好的工具——google(内事不决问google,外事不明问谷歌,须梯子)。 |
| 14 | + |
| 15 | +###操作文件:重命名、删除文件 |
| 16 | + |
| 17 | +在对文件操作的时候,`open()`这个内建函数可以建立、打开文件。但是,如果对文件进行改名、删除操作,就要是用os模块的方法了。 |
| 18 | + |
| 19 | +首先建立一个文件,文件名为22201.py,文件内容是: |
| 20 | + |
| 21 | + #!/usr/bin/env python |
| 22 | + # coding=utf-8 |
| 23 | + |
| 24 | + print "This is a tmp file." |
| 25 | + |
| 26 | +然后将这个文件名称修改为其它的名称。 |
| 27 | + |
| 28 | + >>> import os |
| 29 | + >>> os.rename("22201.py", "newtemp.py") |
| 30 | + |
| 31 | +注意,我是先进入到了文件22201.py的目录,然后进入到python交互模式,所以,可以直接写文件名,如果不是这样,需要将文件名的路径写上。`os.rename("22201.py", "newtemp.py")`中,第一个文件是原文件名称,第二个是打算修改成为的文件名。 |
| 32 | + |
| 33 | + $ ls new* |
| 34 | + newtemp.py |
| 35 | + |
| 36 | +查看,能够看到这个文件。并且文件内容可以用`cat newtemp.py`看看(这是在ubuntu系统,如果是windows系统,可以用其相应的编辑器打开文件看内容)。 |
| 37 | + |
| 38 | + Help on built-in function rename in module posix: |
| 39 | + |
| 40 | + rename(...) |
| 41 | + rename(old, new) |
| 42 | + |
| 43 | + Rename a file or directory. |
| 44 | + |
| 45 | +除了修改文件名称,还可以修改目录名称。请注意阅读帮助信息。 |
| 46 | + |
| 47 | +另外一个os.remove(),首先看帮助信息,然后再实验。 |
| 48 | + |
| 49 | + Help on built-in function remove in module posix: |
| 50 | + |
| 51 | + remove(...) |
| 52 | + remove(path) |
| 53 | + |
| 54 | + Remove a file (same as unlink(path)). |
| 55 | + |
| 56 | +比较简单。那就测试一下。为了测试,先建立一些文件吧。 |
| 57 | + |
| 58 | + $ pwd |
| 59 | + /home/qw/Documents/VBS/StarterLearningPython/2code/rd |
| 60 | + |
| 61 | +这是我建立的临时目录,里面有几个文件: |
| 62 | + |
| 63 | + $ ls |
| 64 | + a.py b.py c.py |
| 65 | + |
| 66 | +下面删除a.py文件 |
| 67 | + |
| 68 | + >>> import os |
| 69 | + >>> os.remove("/home/qw/Documents/VBS/StarterLearningPython/2code/rd/a.py") |
| 70 | + |
| 71 | +看看删了吗? |
| 72 | + |
| 73 | + $ ls |
| 74 | + b.py c.py |
| 75 | + |
| 76 | +果然管用呀。再来一个狠的: |
| 77 | + |
| 78 | + >>> os.remove("/home/qw/Documents/VBS/StarterLearningPython/2code/rd") |
| 79 | + Traceback (most recent call last): |
| 80 | + File "<stdin>", line 1, in <module> |
| 81 | + OSError: [Errno 21] Is a directory: '/home/qw/Documents/VBS/StarterLearningPython/2code/rd' |
| 82 | + |
| 83 | +报错了。我打算将这个目录下的所剩文件删光光。这么做不行。注意帮助中一句话`Remove a file`,os.remove()就是用来删除文件的。并且从报错中也可以看到,告诉我们错误的原因在于那个参数是一个目录。 |
| 84 | + |
| 85 | +要删除目录,还得继续向下学习。 |
| 86 | + |
| 87 | +###操作目录 |
| 88 | + |
| 89 | +**os.listdir**:显示目录中的文件 |
| 90 | + |
| 91 | + Help on built-in function listdir in module posix: |
| 92 | + |
| 93 | + listdir(...) |
| 94 | + listdir(path) -> list_of_strings |
| 95 | + |
| 96 | + Return a list containing the names of the entries in the directory. |
| 97 | + |
| 98 | + path: path of directory to list |
| 99 | + |
| 100 | + The list is in arbitrary order. It does not include the special |
| 101 | + entries '.' and '..' even if they are present in the directory. |
| 102 | + |
| 103 | +看完帮助信息,读者一定觉得这是一个非常简单的方法,不过,特别注意它返回的值是列表,还有就是如果文件夹中有那样的特殊格式命名的文件,不显示。在linux中,用ls命令也看不到这些隐藏的东东。 |
| 104 | + |
| 105 | + >>> os.listdir("/home/qw/Documents/VBS/StarterLearningPython/2code/rd") |
| 106 | + ['b.py', 'c.py'] |
| 107 | + >>> files = os.listdir("/home/qw/Documents/VBS/StarterLearningPython/2code/rd") |
| 108 | + >>> for f in files: |
| 109 | + ... print f |
| 110 | + ... |
| 111 | + b.py |
| 112 | + c.py |
| 113 | + |
| 114 | +**os.getcwd, os.chdir**:当前工作目录,改变当前工作目录 |
| 115 | + |
| 116 | +这两个函数怎么用?惟有通过`help()`看文档啦。请读者自行看看。我就不贴出来了,仅演示一个例子: |
| 117 | + |
| 118 | + >>> cwd = os.getcwd() #当前目录 |
| 119 | + >>> print cwd |
| 120 | + /home/qw/Documents/VBS/StarterLearningPython/2code/rd |
| 121 | + >>> os.chdir(os.pardir) #进入到上一级 |
| 122 | + |
| 123 | + >>> os.getcwd() #当前 |
| 124 | + '/home/qw/Documents/VBS/StarterLearningPython/2code' |
| 125 | + |
| 126 | + >>> os.chdir("rd") #进入下级 |
| 127 | + |
| 128 | + >>> os.getcwd() |
| 129 | + '/home/qw/Documents/VBS/StarterLearningPython/2code/rd' |
| 130 | + |
| 131 | +`os.pardir`的功能是获得父级目录,相当于`..` |
| 132 | + |
| 133 | + >>> os.pardir |
| 134 | + '..' |
| 135 | + |
| 136 | + |
| 137 | +**os.makedirs, os.removedirs**:创建和删除目录 |
| 138 | + |
| 139 | +废话少说,路子还是前面那样,就省略看帮助了,读者可以自己看。直接上例子: |
| 140 | + |
| 141 | + >>> dir = os.getcwd() |
| 142 | + >>> dir |
| 143 | + '/home/qw/Documents/VBS/StarterLearningPython/2code/rd' |
| 144 | + >>> os.removedirs(dir) |
| 145 | + Traceback (most recent call last): |
| 146 | + File "<stdin>", line 1, in <module> |
| 147 | + File "/usr/lib/python2.7/os.py", line 170, in removedirs |
| 148 | + rmdir(name) |
| 149 | + OSError: [Errno 39] Directory not empty: '/home/qw/Documents/VBS/StarterLearningPython/2code/rd' |
| 150 | + |
| 151 | +什么时候都不能得意忘形,一定要谦卑。那就是从看文档开始一点一点地理解。不能像上面那样,自以为是、贸然行事。看报错信息,要删除某个目录,那个目录必须是空的。 |
| 152 | + |
| 153 | + >>> os.getcwd() |
| 154 | + '/home/qw/Documents/VBS/StarterLearningPython/2code' |
| 155 | + |
| 156 | +这是当前目录,在这个目录下再建一个新的子目录: |
| 157 | + |
| 158 | + >>> os.makedirs("newrd") |
| 159 | + >>> os.chdir("newrd") |
| 160 | + >>> os.getcwd() |
| 161 | + '/home/qw/Documents/VBS/StarterLearningPython/2code/newrd' |
| 162 | + |
| 163 | +建立了一个。下面把这个删除了。这个是空的。 |
| 164 | + |
| 165 | + >>> os.listdir(os.getcwd()) |
| 166 | + [] |
| 167 | + >>> newdir = os.getcwd() |
| 168 | + >>> os.removedirs(newdir) |
| 169 | + |
| 170 | +按照我的理解,这里应该报错。因为我是在当前工作目录删除当前工作目录。如果这样能够执行,总觉得有点别扭。但事实上,就行得通了。就算是python的规定吧。不过,让我来确定这个功能的话,还是习惯不能在本地删除本地。 |
| 171 | + |
| 172 | +按照上面的操作,在看当前工作目录: |
| 173 | + |
| 174 | + >>> os.getcwd() |
| 175 | + Traceback (most recent call last): |
| 176 | + File "<stdin>", line 1, in <module> |
| 177 | + OSError: [Errno 2] No such file or directory |
| 178 | + |
| 179 | +目录被删了,当然没有啦。只能回到父级。 |
| 180 | + |
| 181 | + >>> os.chdir(os.pardir) |
| 182 | + >>> os.getcwd() |
| 183 | + '/home/qw/Documents/VBS/StarterLearningPython/2code' |
| 184 | + |
| 185 | +有点不可思议。本来没有当前工作目录,怎么会有“父级”的呢?但python就是这样。 |
| 186 | + |
| 187 | +补充一点,前面说的如果目录不空,就不能用`os.removedirs()`删除。但是,可以用模块shutil的retree方法。 |
| 188 | + |
| 189 | + >>> os.getcwd() |
| 190 | + '/home/qw/Documents/VBS/StarterLearningPython/2code' |
| 191 | + >>> os.chdir("rd") |
| 192 | + >>> now = os.getcwd() |
| 193 | + >>> now |
| 194 | + '/home/qw/Documents/VBS/StarterLearningPython/2code/rd' |
| 195 | + >>> os.listdir(now) |
| 196 | + ['b.py', 'c.py'] |
| 197 | + >>> import shutil |
| 198 | + >>> shutil.rmtree(now) |
| 199 | + >>> os.getcwd() |
| 200 | + Traceback (most recent call last): |
| 201 | + File "<stdin>", line 1, in <module> |
| 202 | + OSError: [Errno 2] No such file or directory |
| 203 | + |
| 204 | +请读者注意的是,对于os.makedirs()还有这样的特点: |
| 205 | + |
| 206 | + >>> os.getcwd() |
| 207 | + '/home/qw/Documents/VBS/StarterLearningPython/2code' |
| 208 | + >>> d0 = os.getcwd() |
| 209 | + >>> d1 = d0+"/ndir1/ndir2/ndir3" #这是想建立的目录,但是中间的ndir1,ndir2也都不存在。 |
| 210 | + >>> d1 |
| 211 | + '/home/qw/Documents/VBS/StarterLearningPython/2code/ndir1/ndir2/ndir3' |
| 212 | + >>> os.makedirs(d1) |
| 213 | + >>> os.chdir(d1) |
| 214 | + >>> os.getcwd() |
| 215 | + '/home/qw/Documents/VBS/StarterLearningPython/2code/ndir1/ndir2/ndir3' |
| 216 | + |
| 217 | +中间不存在的目录也被建立起来,直到做右边的目录为止。与os.makedirs()类似的还有os.mkdir(),不过,`os.mkdir()`没有上面这个功能,它只能一层一层地建目录。 |
| 218 | + |
| 219 | +`os.removedirs()`和`os.rmdir()`也类似,区别也类似上面。 |
| 220 | + |
| 221 | +###文件和目录属性 |
| 222 | + |
| 223 | +不管是在什么操作系统,都能看到文件或者目录的有关属性,那么,在os模块中,也有这样的一个方法:`os.stat()` |
| 224 | + |
| 225 | + >>> p = os.getcwd() #当前目录 |
| 226 | + >>> p |
| 227 | + '/home/qw/Documents/VBS/StarterLearningPython' |
| 228 | + |
| 229 | + #这个目录的有关信息 |
| 230 | + >>> os.stat(p) |
| 231 | + 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) |
| 232 | + |
| 233 | + #指定一个文件 |
| 234 | + >>> pf = p + "/README.md" |
| 235 | + #此文件的信息 |
| 236 | + >>> os.stat(pf) |
| 237 | + 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) |
| 238 | + |
| 239 | +从结果中看,可能看不出什么来,先不用着急。这样的结果是对computer姑娘友好的,对读者可能不友好。如果用下面的方法,就友好多了: |
| 240 | + |
| 241 | + >>> fi = os.stat(pf) |
| 242 | + >>> mt = fi[8] |
| 243 | + |
| 244 | +fi[8]就是st_mtime的值,它代表最后modified(修改)文件的时间。看结果: |
| 245 | + |
| 246 | + >>> mt |
| 247 | + 1429580969 |
| 248 | + |
| 249 | +还是不友好。下面就用time模块来友好一下: |
| 250 | + |
| 251 | + >>> import time |
| 252 | + >>> time.ctime(mt) |
| 253 | + 'Tue Apr 21 09:49:29 2015' |
| 254 | + |
| 255 | +现在就对读者友好了。 |
| 256 | + |
| 257 | +用`os.stat()`能够查看文件或者目录的属性。如果要修改呢?比如在部署网站的时候,常常要修改目录或者文件的权限等。这种操作在python的os模块能做到吗? |
| 258 | + |
| 259 | +要求越来越多了。在一般情况下,不在python里做这个呀。当然,世界是复杂的。肯定有人会用到的,所以os模块提供了`os.chmod()` |
| 260 | + |
| 261 | +###操作命令 |
| 262 | + |
| 263 | +读者如果使用某种linux系统,或者曾经用过dos(恐怕很少),或者再windows里面用过command,对敲命令都不陌生。通过命令来做事情的确是很酷的。比如,我是在ubuntu中,要查看文件和目录,只需要`ls`就足够了。我并不是否认图形界面,而是在某些情况下,还是离不开命令的,比如用程序来完成查看文件和目录的操作。所以,os模块中提供了这样的方法,许可程序员在python程序中使用操作系统的命令。(以下是在ubuntu系统,如果读者是windows,可以将命令换成DOS命令。) |
| 264 | + |
| 265 | + >>> p |
| 266 | + '/home/qw/Documents/VBS/StarterLearningPython' |
| 267 | + >>> command = "ls " + p |
| 268 | + >>> command |
| 269 | + 'ls /home/qw/Documents/VBS/StarterLearningPython' |
| 270 | + |
| 271 | +为了输入方便,我采用了前面例子中已经有的那个目录,并且,用拼接字符串的方式,将要输入的命令(查看某文件夹下的内容)组装成一个字符串,赋值给变量command,然后: |
| 272 | + |
| 273 | + >>> os.system(command) |
| 274 | + 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 |
| 275 | + 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 |
| 276 | + 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 |
| 277 | + 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 |
| 278 | + 0 |
| 279 | + |
| 280 | +这样就列出来了该目录下的所有内容。 |
| 281 | + |
| 282 | +需要注意的是,`os.system()`是在当前进程中执行命令,直到它执行结束。如果需要一个新的进程,可以使用`os.exec`或者`os.execvp`。对此有兴趣详细了解的读者,可以查看帮助文档了解。另外,`os.system()`是通过shell执行命令,执行结束后将控制权返回到原来的进程,但是`os.exec()`及相关的函数,则在执行后不将控制权返回到原继承,从而使python失去控制。 |
| 283 | + |
| 284 | +关于python对进程的管理,此处暂不过多介绍。 |
| 285 | + |
| 286 | +`os.system()`是一个用途不少的函数。曾有一个朋友网上询问,用它来启动浏览器。不过,这个操作的确要非常仔细。为什么呢?演示一下就明白了。 |
| 287 | + |
| 288 | + >>> os.system("/usr/bin/firefox") |
| 289 | + |
| 290 | + (process:4002): GLib-CRITICAL **: g_slice_set_config: assertion 'sys_page_size == 0' failed |
| 291 | + |
| 292 | + (firefox:4002): GLib-GObject-WARNING **: Attempt to add property GnomeProgram::sm-connect after class was initialised |
| 293 | + ...... |
| 294 | + |
| 295 | +我是在ubuntu上操作的,浏览器的地址是`/usr/bin/firefox`,可是,那个朋友是windows,他就要非常小心了,因为在windows里面,表示路径的斜杠是跟上面显示的是反着的,可是在python中`\`这种斜杠代表转义。解决这个问题可以参看[《字符串(1)》](./106)。比较简单的一个方法用`r"c:\user\firfox.exe"`的样式,因为在`r" "`中的,都是被认为原始字符了。还没完,因为windows系统中,一般情况下那个文件不是安装在我演示的那个简单样式的文件夹中,而是`C:\Program Files`,这中间还有空格,所以还要注意,空格问题。简直有点晕头转向了。读者按照这些提示,看看能不能完成用`os.system()`启动firefox的操作呢? |
| 296 | + |
| 297 | +凡事感觉麻烦的东西,必然有另外简单的来替代。于是又有了一个webbrowser模块。可以专门用来打开指定网页。 |
| 298 | + |
| 299 | + >>> import webbrowser |
| 300 | + >>> webbrowser.open("http://www.itdiffer.com") |
| 301 | + True |
| 302 | + |
| 303 | +不管是什么操作系统,只要如上操作就能打开网页了。 |
| 304 | + |
| 305 | +真是神奇的标准库,有如此多的工具,能不加速开发进程吗?能不降低开发成本吗?“人生苦短,我用python”! |
| 306 | + |
| 307 | +------ |
| 308 | + |
| 309 | +[总目录](./index.md) | [上节:标准库(2)](./221.md) | [下节:标准库(4)](./223.md) |
| 310 | + |
| 311 | +如果你认为有必要打赏我,请通过支付宝:**qiwsir@126.com**,不胜感激。 |
0 commit comments