os——可移植的访问操作系统的特定功能
来源:互联网 发布:免费开源java即时通讯 编辑:程序博客网 时间:2024/06/15 07:08
原文地址:https://pymotw.com/3/os/index.html
目的:可移植的访问操作系统的特定功能。
os
模块为平台特定模块(比如posix
,nt
和mac
)提供了一个包装器。所有平台的函数API应该相同,所以使用os
模块提供了一些可移植的措施。但是,不是所有函数在每个平台都有效。本文描述的很多进程管理函数在Windows上无效。
os
模块的Python文档中,它的子标题是“各种操作系统接口”。该模块主要包括创建和管理运行的进程或文件系统的内容(文件和目录)的函数,以及一些其它功能。
1、检查文件系统的内容
使用listdir()
返回文件系统中一个目录的内容列表。
# os_listdir.pyimport osimport sysprint(os.listdir(sys.argv[1]))
返回值是给定目录中所有命名成员的列表。文件,子目录和符号链接之间没有区别。
$ python3 os_listdir.py .['index.rst', 'os_access.py', 'os_cwd_example.py','os_directories.py', 'os_environ_example.py','os_exec_example.py', 'os_fork_example.py','os_kill_example.py', 'os_listdir.py', 'os_listdir.py~','os_process_id_example.py', 'os_process_user_example.py','os_rename_replace.py', 'os_rename_replace.py~','os_scandir.py', 'os_scandir.py~', 'os_spawn_example.py','os_stat.py', 'os_stat_chmod.py', 'os_stat_chmod_example.txt','os_strerror.py', 'os_strerror.py~', 'os_symlinks.py','os_system_background.py', 'os_system_example.py','os_system_shell.py', 'os_wait_example.py','os_waitpid_example.py', 'os_walk.py']
walk()
函数递归遍历一个目录,并为每个子目录生成一个元组,其中包括目录路径,该路径的所有直接子目录,以及一个该目录下所有文件名的列表。
# os_walk.pyimport osimport sys# If we are not given a path to list, use /tmpif len(sys) == 1: root = '/tmp'else: root = sys.argv[1]for dir_name, sub_dirs, files in os.walk(root): print(dir_name) # Make the subdirectory names stand out with / sub_dirs = [n + '/' for n in sub_dirs] # Mix the directory contents together contents = sub_dirs + files contents.sort() # Show the contents for c in contents: print(' {}'.format(c)) print()
这个例子显示一个递归的目录列表。
$ python3 os_walk.py ../zipimport../zipimport __init__.py example_package/ index.rst zipimport_example.zip zipimport_find_module.py zipimport_get_code.py zipimport_get_data.py zipimport_get_data_nozip.py zipimport_get_data_zip.py zipimport_get_source.py zipimport_is_package.py zipimport_load_module.py zipimport_make_example.py../zipimport/example_package README.txt __init__.py
如果需要文件名之外的更多信息,scandir()
比listdir()
更高效,因为扫描目录时只需要执行一次系统调用就能收集更多信息。
# os_scandir.pyimport osimport sysfor entry in os.scandir(sys.argv[1]): if entry.is_dir(): typ = 'dir' elif entry.is_file(): typ = 'file' elif entry.is_symlink(): typ = 'link' else: typ = 'unknow' print('{name} {typ}'.format( name=entry.name, typ=typ, ))
scandir()
返回为目录中的项目返回一个DirEntry
实例的序列。该对象有一些访问文件元数据的属性和方法。
$ python3 os_scandir.py .index.rst fileos_access.py fileos_cwd_example.py fileos_directories.py fileos_environ_example.py fileos_exec_example.py fileos_fork_example.py fileos_kill_example.py fileos_listdir.py fileos_listdir.py~ fileos_process_id_example.py fileos_process_user_example.py fileos_rename_replace.py fileos_rename_replace.py~ fileos_scandir.py fileos_scandir.py~ fileos_spawn_example.py fileos_stat.py fileos_stat_chmod.py fileos_stat_chmod_example.txt fileos_strerror.py fileos_strerror.py~ fileos_symlinks.py fileos_system_background.py fileos_system_example.py fileos_system_shell.py fileos_wait_example.py fileos_waitpid_example.py fileos_walk.py file
2、管理文件系统的权限
使用stat()
和lstat()
(用于检查可能是符号链接的状态)可以访问一个文件的详细信息。
# os_stat.pyimport osimport sysimport timeif len(sys.argv) == 1: filename = __file__else: filename = sys.argv[1]stat_info = os.stat(filename)print('os.stat({}):'.format(filename))print(' Size:', stat_info.st_size)print(' Permissions:', oct(stat_info.st_mode))print(' Owner:', stat_info.st_uid)print(' Device:', stat_info.st_dev)print(' Created :', time.ctime(stat_info.st_ctime))print(' Last modified:', time.ctime(stat_info.st_mtime))print(' Last accessed:', time.ctime(stat_info.st_atime))
输出结果取决于示例代码是如何运行的。尝试在命令行中传递不同的文件名到os_stat.py
中。
$ python3 os_stat.pyos.stat(os_stat.py): Size: 593 Permissions: 0o100644 Owner: 527 Device: 16777218 Created : Sat Dec 17 12:09:51 2016 Last modified: Sat Dec 17 12:09:51 2016 Last accessed: Sat Dec 31 12:33:19 2016$ python3 os_stat.py index.rstos.stat(index.rst): Size: 26878 Permissions: 0o100644 Owner: 527 Device: 16777218 Created : Sat Dec 31 12:33:10 2016 Last modified: Sat Dec 31 12:33:10 2016 Last accessed: Sat Dec 31 12:33:19 2016
在类Unix系统上,可以传递一个整数作为模式给chmod()
,来修改文件权限。模式值可以使用在stat
模块中定义的常量构建。下面这个例子切换用户的执行权限位:
# os_stat_chmod.pyimport osimport statfilename = 'os_stat_chmod_example.txt'if os.path.exists(filename): os.unlink(filename)with open(filename, 'wt') as f: f.write('content')# Determine what permissions are already set using statexisting_permissions = stat.S_IMODE(os.stat(filename).st_mode)if not os.access(filename, os.X_OK): print('Adding excute permission') new_permissions = existing_permissions | stat.S_IXUSRelse: print('Removing execute permission') new_permissions = existing_permissions ^ stat.S_IXUSRos.chmod(filename, new_permissions)
这个脚本假设它具有在运行时修改文件模式所需的权限。
$ python3 os_stat_chmod.pyAdding execute permission
access()
函数用于测试进程对文件的访问权限。
# os_access.pyprint('Testing:', __file__)print('Exists:', os.access(__file__, os.F_OK))print('Readable:', os.access(__file__, os.R_OK))print('Writable:', os.access(__file__, os.W_OK))print('Executable:', os.access(__file__, os.X_OK))
结果取决于如何运行实例代码,但输出类似这样:
$ python3 os_access.pyTesting: os_access.pyExists: TrueReadable: TrueWritable: TrueExecutable: False
access()
的库文档包括两个特殊警告。第一个,在一个文件上调用open()
之前,调用access()
测试文件是否可以被打开没有意义。在这两次调用之间有很短的,但确实存在的时间间隔,期间文件的权限有可能被改变。另一个警告主要适用于扩展自POSIX
权限语义的联网文件系统。某些文件系统类型可能会响应进程有权限访问文件的POSIX
调用,然后由于某些原因没有通过POSIX
调用测试,尝试使用open()
时会出错。总而言之,最好使用需要的模式调用open()
,并捕获出错时抛出的IOError
。
3、创建和删除目录
有几个函数用于操作文件系统中的目录,包括创建,列出内容和删除它们。
# os_directories.pydir_name = 'os_directories_example'print('Creating', dir_name)os.makedirs(dir_name)file_name = os.path.join(dir_name, 'example.txt')print('Creating', file_name)with open(file_name, 'wt') as f: f.write('example file')print('Cleaning up')os.unlink(file_name)os.rmdir(dir_name)
有两个函数集用于创建和删除目录。使用mkdir()
创建一个新目录时,所有父目录必须已经存在。使用rmdir()
删除一个目录时,只有叶子目录(路径的最后一部分)会真正的被删除。相反,makedirs()
和removedirs()
会操作路径中的所有节点。makedirs()
会创建路径中所有不存在的部分,removedirs()
会删除所有父目录,知道它们为空。
$ python3 os_directories.pyCreating os_directories_exampleCreating os_directories_example/example.txtCleaning up
4、使用符号链接
对于支持符号链接的平台和文件系统,有些函数用于符号链接。
# os_symlinks.pyimport oslink_name = '/tmp/' + os.path.basename(__file__)print('Creating link {} -> {}'.format(link_name, __file__))os.symlink(__file__, link_name)stat_info = os.lstat(link_name)print('Permissions:', oct(stat_info.st_mode))print('Points to:', os.readlink(link_name))# Cleanupos.unlink(link_name)
使用symlink()
创建一个符号链接,readlink()
读取链接,确定它指向的原始文件。lstat()
函数类似stat()
,但是它在符号链接上运行。
$ python3 os_symlinks.pyCreating link /tmp/os_symlinks.py -> os_symlinks.pyPermissions: 0o120755Points to: os_symlinks.py
5、安全地替换已存在的文件
替换或重命名已存在文件不是幂等的,并且可能把应用程序暴露于竞争条件。对于这些操作,rename()
和replace()
函数可以在兼容POSIX
系统上使用原子操作来实现安全的算法。
# os_rename_replace.pyimport globimport oswith open('rename_start.txt', 'w') as f: f.write('starting as rename_start.txt')print('Starting:', glob.glob('rename*.txt'))os.rename('rename_start.txt', 'rename_finish.txt')print('After rename:', glob.glob('rename*.txt'))with open('rename_finish.txt', 'r') as f: print('Contents:', repr(f.read()))with open('rename_new_contents.txt', 'w') as f: f.write(ending with contents of rename_new_contents.txt')os.replace('rename_new_contents.txt', 'rename_finish.txt')with open('rename_new_contents.txt', 'r') as f: print('After replace:', repr(f.read()))for name in glob.glob('rename*.txt'): os.unlink(name)
大多数时候,rename()
和replace()
函数可以跨文件系统工作。如果将文件移动到新文件系统,或者目标已经存在,则重命名文件可能会失败。
$ python3 os_rename_replace.pyStarting: ['rename_start.txt']After rename: ['rename_finish.txt']Contents: 'starting as rename_start.txt'After replace: 'ending with contents of rename_new_contents.txt'
6、检测和修改进程所有者
os
提供的下一组函数用于确定和修改进程所有者的ID。这最常被守护程序或特殊系统程序的作者用于修改权限级别,而不是以root身份运行。本节不会解释Unix安全性,进程所有者等的所有错综复杂的细节。有关详细信息请参考本节末尾的参考列表。
下面这个示例显示了一个进程的real和effective用户和组的信息,然后修改effective值。这类似于系统引导期间,守护程序以root身份启动时需要完成一些工作,用于降低权限级别,并以另一个用户运行。
注意:运行示例之前,修改
TEST_GID
和TEST_UID
值为系统中定义的real用户。
# os_process_user_example.pyimport osTEST_GID = 502TEST_UID = 502def show_user_info(): print('User (actual/effective) : {} / {}'.format( os.getuid(), os.geteuid())) print('Group (actual/effective) : {} / {}'.format( os.getgid(), os.getegid())) print('Actual Groups :', os.getgroups())print('BEFORE CHANGE:')show_user_info()print()try: os.setgid(TEST_ID)except OSError: print('ERROR: Could not change effective group. ' 'Rerun as root.')else: print('CHANGE GROUP:') show_user_info() print()try: os.seteuid(TEST_ID)except OSError: print('ERROR: Could not change effective user. ' 'Rerun as root.')else: print('CHANGE USER:') show_user_info() print()
当在OS X上运行的用户ID为502,组为502时,产生以下输出:
$ python3 os_process_user_example.pyBEFORE CHANGE:User (actual/effective) : 527 / 527Group (actual/effective) : 501 / 501Actual Groups : [501, 701, 402, 702, 500, 12, 61, 80, 98, 398,399, 33, 100, 204, 395]ERROR: Could not change effective group. Rerun as root.ERROR: Could not change effective user. Rerun as root.
值不会修改,因为它没有作为root运行,一个进程不能修改它的effective所有者的值。任何设置effective user id或group id为当前用户之外的其它值都会导致OSError
。使用sudo
运行同一个脚本,用root权限开始一个不同的场景。
$ sudo python3 os_process_user_example.pyBEFORE CHANGE:User (actual/effective) : 0 / 0Group (actual/effective) : 0 / 0Actual Groups : [0, 1, 2, 3, 4, 5, 8, 9, 12, 20, 29, 61, 80,702, 33, 98, 100, 204, 395, 398, 399, 701]CHANGE GROUP:User (actual/effective) : 0 / 0Group (actual/effective) : 0 / 502Actual Groups : [0, 1, 2, 3, 4, 5, 8, 9, 12, 20, 29, 61, 80,702, 33, 98, 100, 204, 395, 398, 399, 701]CHANGE USER:User (actual/effective) : 0 / 502Group (actual/effective) : 0 / 502Actual Groups : [0, 1, 2, 3, 4, 5, 8, 9, 12, 20, 29, 61, 80,702, 33, 98, 100, 204, 395, 398, 399, 701]
这种情况下,因为用root启动,所以脚本会修改进程的effective user和group。一旦修改了effective UID,进程会被限制在该用户的权限下。因为非root用户不能修改它们的effective group,所以程序需要在修改用户之前修改组。
7、管理进程环境
操作系统通过os
模块暴露给程序的另一个特征是环境。在环境中设置的变量作为字符串可见,可以通过os.environ
或getenv()
读取。环境变量通常用于配置搜索路径,文件位置和调试标识等值。这个示例显示了如何检索一个环境变量,以及传递一个值给子进程。
# os_environ_example.pyimport osprint('Initial value:', os.environ.get('TESTVAR', None))print('Child process:')os.system('echo $TESTVAR')os.environ['TESTVAR'] = 'THIS VALUE WAS CHANGED'print()print('Changed value:', os.environ['TESTVAR'])print('Child process:')os.system('echo $TESTVAR')del os.environ['TESTVAR']print()print('Remove value:', os.environ.get('TESTVAR', None))print('Child process:')os.system('echo $TESTVAR')
os.environ
对象遵循标准的Python映射API,用于检索和设置值。对os.environ
的修改会为子进程导出。
$ python3 -u os_environ_example.pyInitial value: NoneChild process:Changed value: THIS VALUE WAS CHANGEDChild process:THIS VALUE WAS CHANGEDRemoved value: NoneChild process:
8、管理进程工作目录
带层级文件系统的操作系统有当前工作目录的概念——当用相对路径访问文件时,进程用作起始位置的目录。可以使用getcwd()
查询当前工作目录,使用chdir()
修改。
# os_cwd_example.pyimport osprint('Starting:', os.getcwd())print('Moving up one:', os.pardir)os.chdir(os.pardir)print('After move:', os.getcwd())
os.curdir
和os.pardir
用于指向当前目录和父目录。
$ python3 os_cwd_example.pyStarting: .../pymotw-3/source/osMoving up one: ..After move: .../pymotw-3/source
9、运行外部命令
警告:
用于处理进程的很多函数的移植性是有限制的。要以平台独立的方式,以更一致的方法使用进程,请参考subprocess
模块。
运行独立命令的最基本的,并且不与它交互的方式是使用system()
。它接收单个字符串参数,它是被子进程在shell中执行的命令行。
# os_system_example.pyimport os# Simple commandos.system('pwd')
system()
的返回值是shell执行程序的退出值,它被打包成一个16 bit的数字,其中高字节是退出状态,低字节是导致进程死亡的信号数或者0。
$ python3 -u os_system_example.py.../pymotw-3/source/os
因为命令直接传递给shell处理,所以可以包括shell语法,比如通配符或者环境变量。
# os_system_shell.pyimport os# Command with shell expansionos.system('echo $TMPDIR')
当shell执行命令行时,字符串中的环境变量TMPDIR
会被展开。
$ python3 -u os_system_shell.py/var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T/
除非命令明确地在后台执行,否则调用system()
会阻塞,直到完成执行。默认情况下,子进程的标准输入,输出和错误与调用者拥有的适当流关联,但是可以使用shell语法重定向。
# os_system_background.pyimport osimport timeprint('Calling...')os.system('date; (sleep 3; date) &')print('Sleeping...')time.sleep(5)
尽管这正好掉进了shell的诡计中,但是有更好的方式完成同样的任务。
$ python3 -u os_system_background.pyCalling...Sat Dec 31 12:33:20 EST 2016Sleeping...Sat Dec 31 12:33:23 EST 2016
10、使用os.fork()创建进程
POSIX函数fork()
和exec()
(在Mac OS X,Linux和其它Unix版本下可用)通过os
模块暴露。已经有很多书籍介绍了可靠的使用这些函数,所以在图书馆或书店查阅更多细节,这里只是一个简介。
使用fork()
创建一个新进程,作为当前进程的克隆:
# os_fork_example.pyimport ospid = os.fork()if pid: print('Child process id:', pid)else: print('I am the child')
每次运行示例时,输入取决于系统的状态,但它看起来是这样的:
$ python3 -u os_fork_example.pyChild process id: 29190I am the child
fork
之后会有两个进程执行同样的代码。通过检查fork()
的返回值,告诉程序在哪个进程中。如果值为0,则当前是子进程。如果不为0,则程序在父进程中执行,返回值是子进程的进程ID。
# os_kill_example.pyimport osimport signalimport timedef signal_usr1(signum, frame): "Callback invoked when a signal is received" pid = os.getpid() print('Received USR1 in process {}'.format(pid))print('Forking...')child_pid = os.fork()if child_pid: print('PARENT: Pausing before sending signal...') time.sleep(1) print('PARENT: Signaling {}'.format(child_pid)) os.kill(child_pid, signal.SIGUSR1)else: print('CHILD: Setting up signal handler') signal.signal(signal.SIGUSR1, signal_usr1) print('CHILD: Pausing to wait for signal') time.sleep(5)
父进程可以使用kill()
和signal
模块发送信号到子进程。首先定义一个接收到信号时触发的信号处理器。然后fork()
,并在用kill()
发送USR1
信号之前,在父进程中暂停一小段时间。这个示例用暂停让子进程有时间设置信号处理器。实际程序中,不需要(或者不希望)调用sleep()
。在子进程中设置信号处理器,并休眠一段时间,让父进程发送信号。
$ python3 -u os_kill_example.pyForking...PARENT: Pausing before sending signal...CHILD: Setting up signal handlerCHILD: Pausing to wait for signalPARENT: Signaling 29193Received USR1 in process 29193
在子进程中处理独立行为的一种简单方法是检查fork()
的返回值,然后分支。更复杂的行为可能需要比简单分支更多的独立代码。其它情况下,可能需要包装已经存在的程序。对于这两种情况,exec*()
函数系列可以用于运行其它程序。
# os_exec_example.pyimport oschild_pid = os.fork()if child_pid: os.waitpid(child_pid, 0)else: os.execlp('pwd', 'pwd', '-P')
当程序通过exec()
运行时,该程序的代码会替换已存在进程中的代码。
$ python3 os_exec_example.py.../pymotw-3/source/os
根据参数的可用形式,父进程的路径和环境是否应该拷贝到子进程中等,exec()
有很多变体。对于所有变种,第一个参数是路径或文件名,剩余的参数控制程序如何执行。它们作为命令行参数传递,或者覆盖进程环境(参考os.environ
和os.getenv
)。完整细节请参考库文档。
11、等待子进程
很多计算密集型程序使用多进程来解决Python和全局解释器锁的线程限制。当启动多个进程执行独立的任务时,主机需要等待其中一个或多个进程完成,然后再启动新进程,以避免服务器超负荷。使用wait()
和相关函数有几种不同的方式。
不管哪个子进程先退出不重要时,使用wait()
。一旦任何子进程退出就会返回。
# os_wait_example.pyimport osimport sysimport timefor i in range(2): print('PARENT {}: FORKING {}'.format(os.getpid(), i)) worker_pid = os.fork() if not worker_pid: print('WORKER {}: Starting'.format(i)) time.sleep(2 + i) print('WORKER {}: Finishing'.format(i)) sys.exit(i)for i in range(2): print('PARENT: Waiting for {}'.format(i)) done = os.wait() print('PARENT: Child done:', done)
wait()
的返回值是一个元组,其中包括进程ID和组合为16 bit值的退出状态。低字节是杀死进程的信号数字,高字节是进程退出时返回的状态码。
$ python3 -u os_wait_example.pyPARENT 29202: Forking 0PARENT 29202: Forking 1PARENT: Waiting for 0WORKER 0: StartingWORKER 1: StartingWORKER 0: FinishingPARENT: Child done: (29203, 0)PARENT: Waiting for 1WORKER 1: FinishingPARENT: Child done: (29204, 256)
使用waitpid()
等待指定进程。
# os_waitpid_example.pyimport osimport sysimport timeworkers = []for i in range(2): print('PARENT {}: Forking {}'.format(os.getpid(), i)) worker_pid = os.fork() if not worker_pid: print('WORKER {}: Starting'.format(i)) time.sleep(2 + i) print('WORKER {}: Finishing'.format(i)) sys.exit(i) workers.append(worker_pid)for pid in workers: print('PARENT: Waiting for {}'.format(pid)) done = os.waitpid(pid, 0) print('PARENT: Child done:', done)
传递目标进程的进程ID,waitpid()
会阻塞直到该进程退出。
$ python3 -u os_waitpid_example.pyPARENT 29211: Forking 0PARENT 29211: Forking 1PARENT: Waiting for 29212WORKER 0: StartingWORKER 1: StartingWORKER 0: FinishingPARENT: Child done: (29212, 0)PARENT: Waiting for 29213WORKER 1: FinishingPARENT: Child done: (29213, 256)
wait3()
和wait4()
以类似的方式工作,但是会返回子进程更详细的信息,包括pid
,退出状态和资源使用情况。
12、生成新进程
为了方便,spawn()
函数族在一条语句中处理fork()
和exec()
:
# os_spawn_example.pyimport osos.spawnlp(os.P_WAIT, 'pwd', 'pwd', '-P')
第一个参数是模式,指定返回之前是否等待进程完成。这个示例中等待进程完成。使用P_NOWAIT
让其它进程启动,然后在当前进程中继续。
$ python3 os_spawn_example.py.../pymotw-3/source/os
13、操作系统错误码
由操作系统定义,并在errno
模块中管理的错误码可以使用strerror()
翻译为消息字符串。
# os_strerror.pyimport errnoimport osfor num in [errno.ENOENT, errno.EINTR, errno.EBUSY]: name = errno.errorcode[num] print('[{num:>2}] {name:<6}: {msg}'.format( name=name, num=num, msg=os.strerror(num)))
这个示例显示了与某些频繁出现的错误代码相关联的消息。
$ python3 os_strerror.py[ 2] ENOENT: No such file or directory[ 4] EINTR : Interrupted system call[16] EBUSY : Resource busy
参考
- os的标准库文档
- Python2到3的移植笔记
- signal ——
signal
模块部分更详细地介绍了信号处理技术。- subprocess ——
subprocess
模块代替os.popen()
。- multiprocessing ——
multiprocessing
模块可以更容易地使用额外进程。- tempfile ——
tempfile
模块用于使用临时文件。- 使用目录树 ——
shutil
模块还包括使用目录树的函数。- Speaking UNIX, Part 8. —— 学习UNIX的多任务。
- Standard streams —— 近一步讨论
stdin
,stdout
和stderr
。- Delve into Unix Process Creation —— 解释Unix进程的生命周期。
- Advanced Programming in the UNIX(R) Environment By W. Richard Stevens and Stephen A. Rago. Published by Addison-Wesley Professional, 2005. ISBN-10: 0201433079 —— 这本书覆盖了多进程,比如处理信号,关闭重复的文件描述符等。
- os——可移植的访问操作系统的特定功能
- 一种支持内存共享的简捷工具—— POSIX(可移植操作系统接口)
- 基于MSP430F5529的μc/os嵌入式实时操作系统移植
- 桥接模式:从操作系统的可移植性说起
- 移植uC/OS-II到瑞萨的单片机,添加信号量功能
- Exchange的“数据库可移植性”功能测试心得
- DSP56311的操作系统移植
- 配置自己的UC/OS—II操作系统
- 配置自己的UC/OS—II操作系统
- 访问特定位置的内存
- OS—操作系统
- OS—操作系统
- uC/OS-II实时操作系统在嵌入式平台上进行移植的一般方法和技巧
- 实时操作系统μC/OS-II在MCF5272上的移植
- uC/OS-II 实时操作系统在嵌入式平台进行移植的一般方法和技巧
- 嵌入式实时操作系统μC/OS-Ⅱ 在DSP芯片上的移植与测试
- UC/OS-II 操作系统移植
- UC/OS-II 操作系统移植
- Hibernate学习笔记01
- <!DOCTYPE html>很重要
- hacker的思想
- hiho一下 第156周 岛屿
- suse12: docker 限制内存, 报your kernel not support swap limit capabilities,memory limited without swap
- os——可移植的访问操作系统的特定功能
- 设计模式--单例模式--Java实现
- android 修改项目名称
- hdu5113-四色定理-搜索&&剪枝&&坑点多多
- Linux系统改变ls文件和文件夹颜色方法
- IDEA版本控制的文件颜色
- 架构、框架、设计模式简述
- 警告:不能通过‘...’传递有非简单旧数据类型‘struct std::string’的对象
- ORACLE的别名不能进行运算