一、使用pathlib模块操作目录
pathlib模块提供了一组面向对象的类,这些类可代表各种操作系统上的路径,程序可通过这些类操作路径。
该模块包含了以下类:
● PurePath:代表并不访问实际文件系统的“纯路径”。PurePath只负责对路径字符串执行操作,并不关心字符串是否是真实路径。该类有两个子类(PurePosixPath)和(PureWindowsPath),分别为UNIX风格和Windows风格。
UNIX风格的路径和Windows风格的路径主要区别在于根路径和路径分隔符:UNIX风格的路径的根路径是斜杠(/),而windows风格的路径的根路径是盘符(c:);UNIX风格的路径分隔符是斜杠(/),而windows风格的路径的分隔符是反斜杠(\)。
● Path:代表访问实际文件系统的“真正路径”。Path对象可用于判断对应的文件是否存在、是否为文件、是否为目录等。Path同样有两个子类,PosixPath和WindowsPath。
(一)PurePath的基本功能
使用PurePath创建PurePath对象会自动识别操作系统,在UNIX或Mac OS X系统上会返回PurePosixPath对象,在Windows系统上则返回PureWindowsPath对象。也可以使用PurePosixPath或PureWindowsPath类明确指定要创建的对象是什么类型的。
创建PurePath和Path时可以传入单个路径字符串,也可以传入多个路径字符串,PurePath会自动将他们拼接成一个字符串。
from pathlib import *
# 创建PurePath,实际上使用PureWindowsPath
pp = PurePath('setup.py')
print(type(pp)) #
pp = PurePath('ib-top', 'some/path', 'info')
# 看到输出Wiondows风格的路径
print(pp) # 'ib-top\some\path\info'
pp = PurePath(Path('ib-top'), Path('info'))
# 看到输出Windows风格的路径
print(pp) # 'ib-top\info'
# 明确指定创建PurePosixPath
pp = PurePosixPath('ib-top', 'some/path', 'info')
# 看到输出UNIX风格的路径
print(pp) # 'ib-top/some/path/info'
如果创建PurePath时不传入任何参数,则会默认为创建当前路径的PurePath,也就是相当于传入了一个点号(.代表当前路径)作为参数。
如果在创建PurePath时传入了多个路径参数,则最后一个根路径及后面的子路径生效:
pp = PurePosixPath('/etc', '/usr', 'lib64')
print(pp) # /usr/lib64
pp = PureWindowsPath('c:/Windows', 'd:/info')
print(pp) # d:/info
※在windows风格的路径中,只有盘符才算根路径,仅有斜杠不算。
pp = PureWindowsPath('c:/windows', '/Program Files')
print(pp) # c:\Program Files
创建PurePath时传入路径包含多余的斜杠和点号会被系统忽略,除了两个点号(..),因为两个点号代表上一级路径。
pp = PurePath('foo//bar')
print(pp) # foo\bar
pp = PurePath('foo/./bar')
print(pp) # foo\bar
pp = PurePath('foo/../bar')
print(pp) # foo\..\bar,相当于找和foo同一级的bar路径
PurePath对象支持比较运算符
from pathlib import *
# 比较两个UNIX风格的路径,区分大小写
print(PurePosixPath('info') == PurePosixPath('INFO')) # False
# 比较两个Windows风格的路径,不区分大小写
print(PureWindowsPath('info') == PureWindowsPath('INFO')) # True
# windows风格路径不区分大小写
print(PureWindowsPath('INFO') in {PureWindowsPath('info')}) # True
# UNIX风格的路径区分大小写,所以'D:'小于'c:'
print(PurePosixPath('D:') < PurePosixPath('c:')) # True
# windows风格路径不区分大小写,所以'd:'(D:)大于'c:'
print(PureWindowsPath('D:') < PureWindowsPath('c:')) # False
# 不同风格的路径可以判断是否相等(总不相等)
print(PureWindowsPath('ib-top') == PurePosixPath('ib-top')) # False
# 不同风格的路径不能判断大小,否则会引发错误
# print(PureWindowsPath('info') < PurePosixPath('info')) # TypeError
# PurePath对象支持斜杠(/)运算符,将多个路径链接起来
pp = PureWindowsPath('abc')
# 将多个路径连接起来(Windows风格的路径)
print(pp / 'xyz' / 'wawa') # abc\xyz\wawa
pp = PurePosixPath('abc')
# 将多个路径连接起来(UNIX风格路径)
print(pp / 'xyz' / 'wawa') # abc/xyz/wawa
pp2 = PurePosixPath('haha', 'hehe')
# 将pp、pp2两个路径连接起来
print(pp / pp2) # abc/haha/hehe
# PurePath的本质其实就是字符串,可以使用str()将他们恢复成字符串对象
pp = PureWindowsPath('abc', 'xyz', 'wawa')
print(str(pp)) # abc\xyz\wawa
pp = PurePosixPath('abc', 'xyz', 'wawa')
print(str(pp)) # abc/xyz/wawa
(二)PurePath的属性和方法
属性/方法 | 描述 |
PurePath.parts | 返回路径字符串中所包含的各部分 |
PurePath.drive | 返回路径字符串中的驱动器盘符 |
PurePath.root | 返回路径字符串中的根路径 |
PurePath.anchor | 返回路径字符串中的盘符和根路径 |
PurePath.parents | 返回当前路径的全部父路径 |
PurePath.parent | 返回当前路径的上一级路径,相当于parents[0]的返回值 |
PurePath.name | 返回当前路径中的文件名 |
PurePath.suffixes | 返回当前路径中的文件所有后缀名 |
PurePath.suffix | 返回当前路径中的文件后缀名,相当于suffixes属性返回的列表的最后一个元素 |
PurePath.stem | 返回当前路径中的主文件名 |
PurePath.as_posix() | 将当前路径转换为UNIX风格的路径 |
PurePath.as_uri() | 将当前路径转换成URI。只有绝对路径才能转换,否则会引发ValueError |
PurePath.is_absolute() | 判断当前路径是否为绝对路径 |
PurePath.joinpath(*other) | 将多个路径连接在一起,类似于斜杠运算符 |
PurePath.match(pattern) | 判断当前路径是否匹配指定通配符 |
PurePath.relative_to(*other) | 获取当前路径中去除基准路径之后的结果 |
PurePath.with_name(name) | 将当前路径中的文件名替换成新文件名。如果当前路径中没有文件名,则引发ValueError |
PurePath.with_suffix(suffix) | 将当前路径中的文件后缀名替换成新的后缀名。如果当前路径中没有后缀名,则添加 |
from pathlib import *
# 访问drive属性
print(PureWindowsPath('c:/Program Files/').drive) # c:
print(PureWindowsPath('/Program Files/').drive) # ''
print(PurePosixPath('/etc').drive) # ''
# 访问root属性
print(PureWindowsPath('c:/Program Files/').root) # \
print(PureWindowsPath('c:Program Files/').root) # ''
print(PurePosixPath('/etc').root) # /
# 访问anchor属性
print(PureWindowsPath('c:/Program Files/').anchor) # c:\
print(PureWindowsPath('c:Program Files/').anchor) # c:
print(PurePosixPath('/etc').anchor) # /
# 访问parents属性
pp = PurePath('abc/xyz/wawa/haha')
print(pp.parents[0]) # abc\xyz\wawa
print(pp.parents[1]) # abc\xyz
print(pp.parents[2]) # abc
print(pp.parents[3]) # .
# 访问parent属性
print(pp.parent) # abc\xyz\wawa
# 访问name属性
print(pp.name) # haha
pp = PurePath('abc/wawa/bb.txt')
print(pp.name) # bb.txt
pp = PurePath('abc/wawa/bb.txt.tar.zip')
# 访问suffixes属性
print(pp.suffixes[0]) # .txt
print(pp.suffixes[1]) # .tar
print(pp.suffixes[2]) # .zip
# 访问suffix属性
print(pp.suffix) # .zip
print(pp.stem) # bb.txt.tar
pp = PurePath('abc', 'xyz', 'wawa', 'haha')
print(pp) # abc\xyz\wawa\haha
# 转换成UNIX风格路径
print(pp.as_posix()) # abc/xyz/wawa/haha
# 将相对路径转换成URI引发异常
# print(pp.as_uri()) # ValueError
# 创建绝对路径
pp = PurePath('d:/', 'Python', 'Python3.6')
# 将绝对路径转换成URI
print(pp.as_uri()) # file:///d:/Python/Python3.6
# 判断当前路径是否匹配指定通配符
print(PurePath('a/b.py').match('*.py')) # True
print(PurePath('/a/b/c.py').match('b/*.py')) # True
print(PurePath('/a/b/c.py').match('a/*.py')) # False
pp = PurePosixPath('c:/abc/xyz/wawa')
# 测试relative_to方法
print(pp.relative_to('c:/')) # abc\xyz\wawa
print(pp.relative_to('c:/abc')) # xyz\wawa
print(pp.relative_to('c:/abc/xyz')) # wawa
# 测试with_name方法
p = PureWindowsPath('e:/Donloads/pathlib.tar.gz')
print(p.with_name('ib-top.py')) # e:\Downloads\ib-top.py
p = PureWindowsPath('c:/')
# print(p.with_name('ib-top.py')) # ValueError
# 测试with_suffix方法
p = PureWindowsPath('e:/Downloads/pathlib.tar.gz')
print(p.with_suffix('.zip')) # e:\Downloads\pathlib.tar.zip
p = PureWindowsPath('README')
print(p.with_suffix('.txt')) # README.TXT
(三)Path的功能和用法
Path与PurePath的用法类似,不同的是PurePath的本质还是字符串,而Path会真正访问底层文件系统,包括判断Path对应的路径是否存在,获取Path对应路径的各种属性(如是否只读、是文件还是文件夹等),并且可以对文件进行读写。
同样的Path也有两个子类,分别代表UNIX风格和Windows风格路径,PosixPath和WindowsPath。
iterdir()方法返回Path对应目录下的所有子目录和文件。glob()方法,用于获取Path对应目录及子目录下匹配指定模式的所有文件。
from pathlib import *
# 获取当前目录
p = Path('.')
# 遍历当前目录下的所有文件和子目录
for x in p.iterdir():
print(x)
# 获取上一级目录
p = Path('../')
# 获取上级目录及其所有子目录下的.py文件
for x in p.glob('**/*.py'):
print(x)
# 获取g:/publish/codes对应的目录
p = Path('g:/publish/codes')
# 获取上级目录及其所有子目录下的.py文件
for x in p.glob('**/Path_test1.py'):
print(x)
除了基本的目录操作,Path还提供了read_bytes()和read_text(encoding=None, errors=None)方法,分别用于读取该Path对应的字节数据(二进制数据)和文本数据;也提供了write_bytes(data)和write_text(data, encoding=None, errors=None)方法来输出字节数据(二进制数据)和文本数据。
from pathlib import *
p = Path('a_test.txt')
# 指定以GBK字符集输出文本内容
result = p.write_text('''
有一个美丽的新世界
它在远方等我
那里有天真的孩子
还有姑娘的酒窝''', encoding='GBK')
# 返回输出的字符数
print(result)
# 指定以GBK字符集读取文本内容
content = p.read_text(encoding='GBK')
# 输出所读取的文本内容
print(content)
# 读取字节内容
bb = p.read_bytes()
print(bb)
二、使用os.path操作目录
在os.path模块下提供了一些操作目录的方法,这些函数可以操作系统的目录本身。该模块提供了exists()函数判断该目录是否存在;也提供了getctime()、getmtime()、getatime()函数来获取该目录的创建时间、最后一次修改时间、最后一次访问时间;还提供了getsize()函数来获取指定文件的大小。
import os
import time
# 获取绝对路径
print(os.path.abspath("a_test.txt")) # 当前路径下的a_test.txt
# 获取共同前缀名
print(os.path.commonprefix(['/user/lib', '/usr/local/lib'])) # /usr/l
# 获取共同路径
print(os.path.commonpath(['/usr/lib', '/usr/local/lib'])) # \usr
# 获取目录
print(os.path.dirname('abc/xyz/README.txt')) # abc/xyz
# 判断指定目录是否存在
print(os.path.exists('abc/xyz/README.txt')) # False
# 获取最近一次访问时间
print(time.ctime(os.path.getatime('os_path_test.py')))
# 获取最后一次修改时间
print(time.ctime(os.path.getmtime('os_path_test.py')))
# 获取创建时间
print(time.ctime(os.path.getctime('os_path_test.py')))
# 获取文件大小
print(os.path.getsize('os_path_test.py'))
# 判断是否为文件
print(os.path.isfile('os_path_test.py')) # True
# 判断是否为目录
print(os.path.isdir('os_path_test.py')) # False
# 判断是否为同一个文件
print(os.path.samefile('os_path_test.py', './os_path_test.py')) # True
三、使用fnmatch处理文件名匹配
fnmatch模块可以支持类似于UNIX shell风格的文件名匹配。
fnmatch支持如下通配符:
通配符 | 描述 |
* | 可匹配任意个任意字符 |
? | 可匹配一个任意字符 |
[字符序列] | 可匹配括号里字符序列中的任意字符。该字符序列也支持中划线表示法。如[a-c]可代表a、b和c字符中任意一个。 |
[!字符序列] | 可匹配不在括号中字符序列中的任意字符。 |
fnmatch.fnmatch(filename, pattern):判断指定文件名是否匹配指定pattern。
fnmatch.fnmatchcase(filename, pattern):该函数与fnmatch.fnmatch的功能大致相同,只是该函数区分大小写。
fnmatch.filter(names, pattern):该函数对names列表进行过滤,返回names列表中匹配pattern的文件名组成的子集合。
fnmatch.translate(pattern):该函数用于将一个UNIX shell风格的pattern转换为正则表达式pattern。
from pathlib import *
import fnmatch
# 遍历当前目录下的所有文件和子目录
for file in Path('.').iterdir():
# 访问所有以_test.py结尾的文件
if fnmatch.fnmatch(file, '*_test.py'):
print(file)
names = ['a.py', 'b.py', 'c.py', 'd.py']
# 对names列表进行过滤
sub = fnmatch.filter(names, '[ac].py')
print(sub) #['a.py', 'c.py']
print(fnmatch.translate('?.py')) # (?s:.\.py)\Z
print(fnmatch.translate('[ac].py')) # (?s:[ac]\.py\Z
print(fnmatch.translate('[a-c].py')) # (?s:[a-c]\.py\Z
四、打开文件
Python提供了一个内置的open()函数,该函数用于打开指定文件。该函数语法格式如下:
open(file_name, [, access_mode][, buffering])
open函数只有第一个参数是必须的,代表要打开文件的路径。
文件对象支持如下属性:
● file.closed:返回文件是否已经关闭。
● file.mode:返回被打开文件的访问模式。
● file.name:返回文件的名称。
# 以默认方式打开文件
f = open('open_test.py')
# 所访问文件的编码方式
print(f.encoding) # cp936
# 所访问文件的访问模式
print(f.mode) # r
# 所访问文件是否已经关闭
print(f.closed) # False
# 所访问文件对象打开的文件名
print(f.name) # open_test.py
(一)文件打开模式
模式 | 意义 |
r | 只读模式 |
w | 写模式 |
a | 追加模式 |
+ | 读写模式,可与其他模式结合使用。如r+代表读写模式,w+也代表读写模式 |
b | 二进制模式,可与其他模式结合使用。如rb代表二进制制度模式,rb+代表二进制读写模式,ab代表二进制追加模式 |
虽然r+和w+都是读写模式,区别是r+要求被打开文件是已存在文件,而w+没有这个限制。
(二)缓冲
如果不使用缓冲,就必须等外设输入或输出一个字节后,内存中的程序才能输出或输入一个字节。使用缓冲后,当程序执行输出时,会先将数据输出到缓冲区中,而不用等待外设同步输出,输入亦然。
open()函数的第三个参数为0(或False)时,打开的文件不带缓冲,如果是1(或者True),就带缓冲区,如果是大于1的整数,则该整数用于指定缓冲区大小,如果是任何负数,代表使用默认缓冲区大小。
五、读取文件
(一)按字节或字符读取
read()方法按字节或字符读取文件内容,如果使用了b模式,则每次读取一个字节,如果没有使用b模式,则每次读取一个字符。
f = open("test.txt", 'r', True, encoding='utf-8')
while True:
# 每次读取一个字节
ch = f.read(1)
# 如果没有读取到数据,则跳出循环
if not ch:
break
# 输出ch
print(ch, end='')
f.close()
如果调用read()方法时不传入参数,该方法默认会读取全部文件内容。
Windows平台,open()函数总是使用GBK字符集,如果要读取的文件所使用的字符集和当前操作系统的字符集不匹配,有三种解决方式:
● 使用二进制模式读取,然后使用bytes的decode()方法恢复成字符串
● 利用codecs模块的open函数来打开文件,该函数在打开文件时允许指定字符集
● 为open()函数指定关键字参数encoding
(二)按行读取
● readline([n]):读取一行美容,如果指定了参数n,则只读取次行内的n个字符。
● readlines():读取文件内所有行
(三)使用fileinput读取多个输入流
fileinput模块可以把多个输入流合并在一起。
● fileinput.input(files=None, inplace=False, backup='', bufsize=0, mode='r', openhook=None),该函数返回一个FileInput对象。
参数解释:
files:文件的路径列表,默认是stdin方式,多文件可以这样传递:['1.txt', '2.txt',....]
inplace:是否将标准输出的结果写回文件,默认不取代
backup:备份文件的扩展名,只指定扩展名,如.bak。如果该文件的备份文件已存在,则会自动覆盖。
bufsize:缓冲区大小,默认为0,如果文件很大,可以修改此参数,一般默认即可
mode:读写模式,默认为只读
openhook:该钩子用于控制打开的所有文件,比如编码方式等
全局函数 | 描述 |
fileinput.filename() | 返回正在读取的文件的文件名 |
fileinput.fileno() | 返回当前文件的文件描述符(file descriptor),该文件描述符是一个整数 |
fileinput.lineno() | 返回当前读取的行号 |
fileinput.filelineno() | 返回当前读取的行在其文件中的行号 |
fileinput.isfirstline() | 返回当前读取的行在其文件中是否为第一行 |
fileinput.isstdin() | 返回最后一行是否从sys.stdin读取。程序可以使用“-”代表从sys.stdin读取 |
fileinput.nextfile() | 关闭当前文件,开始读取下一个文件 |
fileinput.close() | 关闭FileInput对象。 |
(四)文件迭代器
文件对象本身就是可遍历的,所以可以使用for循环来遍历文件内容。
sys.stdin也是一个类文件对象(类似于文件的对象,Python的很多I/O流都是类文件对象)
(五)管道输入
管道的作用:将前一个命令的输出,当成下一个命令的输入。
语法:
cmd1 | cmd2 | cmd3 ...
作用:cmd1命令的输出,将会传给cmd2命令作为输入,cmd2命令的输出又传递给cmd3命令作为输入。
(六)使用with语句
Python提供了with语句来管理资源关闭。with语句的语法格式如下:
with context_expression [as atrget(s)]:
with 代码块
使用with语句管理的资源必须是一个实现上下文管理协议(context manage protocol)的类,这个类的对象可被称为上下文管理器。要实现上下文管理协议,必须实现如下两个方法:
● context_manager.__enter__():进入上下文管理器自动调用的方法。该方法会在with代码块之前执行。如果with语句有as子句,那么该方法的返回值会被赋值给as子句后的变量:该方法可以返回多个值,因此,在as子句后也可以指定多个变量(多个变量必须由“()”括起来组成元组)。
● context_manage.__exit__(exc_type, exc_value, exc_traceback):退出上下文管理器自动调用的方法。该方法会在with代码块执行之后执行。如果with代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为None:如果with代码块因为异常而中止,程序也自动调用该方法,使用sys.exc_info得到异常信息将作为调用该方法的参数。
class FkResource:
def __init__(self, tag):
self.tag = tag
print('构造方法,初始化资源:%s' % tag)
# 定义__enter__方法,在with代码块执行之前执行的方法
def __enter__(self):
print('[__enter__ %s]:' % self.tag)
# 将返回值作为as子句后的变量的值
return 'fkit' # 可以返回任意类型的值
# 定义__exit__方法,在with代码块执行之后执行的方法
def __exit__(self, exc_type, exc_val, exc_traceback):
print('[__exit__ %s]:' % self.tag)
# exc_traceback为None,代表没有异常
if exc_traceback is None:
print('没有异常时关闭资源')
else:
print('遇到异常时关闭资源')
return False # 可以省略,默认返回None,也被看作是False
with FkResource('孙悟空') as dr:
print(dr)
print('[with代码块] 没有异常')
print('-------------------------------')
with FkResource('白骨精'):
print('[with代码块] 异常之前的代码')
raise Exception
print('[with代码块] ~~~~~~~~异常之后的代码')
(七)使用linecache随机读取指定行
linecache模块允许从Python源文件中随机读取指定行,并在内部使用缓存优化存储。
常用函数:
● linecache.getline(filename, lineno, module_globals=None):读取指定模块中指定文件的指定行。filename文件名,lineno指定行号。
● linecache.clearcache():清空缓存
● linecache.checkcache(filename=None):检查缓存是否有效。如果没有指定filename参数,默认检查所有缓存的数据。
六、写文件
r+、w、w+、a、a+模式都可以写入,区别在于r+、w、w+模式打开文件时,文件指针位于文件开头处,a、a+模式打开文件时,文件指针位于文件结尾处。
(一)文件指针的概念
文件指针用于标明文件读写的位置。
● seek(offset[, whence]):该方法把文件指针移动到指定位置。当whence为0时(默认值)表明从文件开头开始计算,如将offset设置为3,就是将文件指针移动到第3处,当whence为1时,表明从指针当前位置开始计算,当whence为2时,表明从文件结尾开始计算。
● tell():判断文件指针的位置。
f = open('filept_test.py', 'rb')
# 判断文件指针的位置
print(f.tell()) # 0
# 将文件指针移动到3处
f.seek(3)
print(f.tell()) # 3
# 读取一个字节,文件指针自动后移1个数据
print(f.read(1)) # 0
print(f.tell()) # 4
# 将文件指针移动到第5处
f.seek(5)
print(f.tell()) # 5
# 将文件指针向后移动5个数据
f.seek(5, 1)
print(f.tell()) # 10
# 将文件指针移动到倒数第10处
f.seek(-10, 2)
print(f.tell())
print(f.read(1)) # d
(二)输出内容
文件对象提供的写文件方法主要由两个:
● write(str或bytes):输出字符串或字节串。只有以二进制模式(b模式)打开的文件才能写入字节串。
● writelines(可迭代对象):输出多个字符串多个字节串。
七、os模块的文件和目录函数
(一)与目录相关的函数
函数 | 描述 |
os.getcwd() | 获取当前目录 |
os.chdir(path) | 改变当前目录 |
os.fchdir(fd) | 通过文件描述符改变当前目录。该函数与上一个函数的功能类似,只是该函数以文件描述符作为参数来代表目录 |
os.chroot(path) | 改变当前进程的根目录 |
os.listdir(path) | 返回path对应目录下的所有文件和子目录 |
os.mkdir(path[, mode]) | 创建path对应的目录,其中mode用于指定该目录的权限。该mode参数代表一个UNIX风格的权限,如0o777代表所有者可读/可写/可执行 |
os.makedirs(path[, mode]) | 作用类似于mkdir(),它可以递归创建目录。如abc/xyz/wawa目录,如果当前目录下没有abc目录,那么使用mkdir()会报错,而makedirs则会递归创建所有目录 |
os.rmdir(path) | 删除path对应的空目录。如果目录非空,则抛出OSError异常,程序可以先使用os.remove()删除文件 |
os.removedirs(path) | 递归删除目录。 |
os.rename(src, dst) | 重命名文件或目录,将src重命名为dst |
os.renames(old, new) | 对文件或目录进行递归重命名。 |
(二)与权限相关的函数
函数 | 描述 |
os.access(path, mode) | 检查path对应的文件或目录是否具有指定权限。该函数的第二个参数可以是一下四个状态值的一个或多个: ● os.F_OK:判断是否存在 ● os.R_OK:判断是否可读 ● os.W_OK:判断是否可写 ● os.X_OK:判断是否可执行 |
os.chmod(path, mode) | 更改权限。其中mode参数代表要改变的权限,该参数支持一下值的组合: ● stat.S_IXOTH:其他用户有执行权限。● stat._S_IWOTH:其他用户有写权限 ● stat.S_TROTH :其他用户有读权限。● stat.S_IRWXO :其他用户有全部权限。 ● stat.S_IXGRP:组用户有执行权限。● stat.S_IWGRP :组用户有写权限。 ● stat.S_IRGRP :组用户有读权限。● stat.S_IRWXG :组用户有全部权限。 ● stat.S_IXUSR:所有者有执行权限。● stat.S_IWUSR : 所有者有写权限。 ● stat.S_IRUSR :所有者有读权限。● stat.S_IRWXU :所有者有全部权限。 ● stat.S_IREAD: Windows 将该文件设为只读的。● stat.S_IWRITE: Windows 将该文件设为可写的。 |
os.chown(path, uid, gid) | 更改文件的所有者。其中uid代表用户id,gid代表组id。该命令在UNIX文件系统下有效 |
os.fchmod(fd, mode) | 改变一个文件的访问权限,该文件由文件描述符fd指定。 |
os.fchown(fd, uid, gid) | 改变文件的所有者,该文件由文件描述符fd指定。 |
(三)与文件访问相关的函数
函数 | 描述 |
os.open(file, flags[, mode]) | 打开一个文件,并且设置打开选项,mode参数可选。该函数返回文件描述符。其中flags代表打开文件的旗标,支持如下一个或多个选项: ● os.O_RDONLY :以只读的方式打开。 ● os.O_WRONLY :以只写的方式打开。 ● os.O_RDWR:以读写的方式打开。 ● os.O_NONBLOCK :打开时不阻塞。 ● os.O_APPEND :以追加的方式打开。 ● os.O_CREAT :创建井打开一个新文件。 ● os.O_TRUNC :打开一个文件并截断它的长度为0 (必须有写权限〉。 ● os.O_EXCL :在创建文件时,如果指定的文件存在,则返回错误。 ● os.O_SHLOCK:自动获取共享锁。 ● os.O_EXLOCK :在|动获取独立锁。 ● os.O_DIRECT :消除或减少缓存效果。 ● os.O_FSYNC :同步写入。 ● os.O_NOFOLLOW :不追踪软链接。 |
os.read(fd, n) | 从文件描述符fd中读取最多n个字节,返回读到的字节串。如果文件描述符fd对应的文件已达到结尾,则返回一个空字符串 |
os.write(fd, str) | 将字节串写入文件描述符fd中,返回实际写入的字节串长度 |
os.close(fd) | 关闭文件描述符fd |
os.lseek(fd, pos, how) | 该函数同样用于一定文件指针。其中how参数指定从哪里开始移动,how=0或者SEEK_SET,从文件开头开始移动;how=1或SEEK_CUR,从当前位置开始移动;how=2或SEEK_END,从文件结束处开始移动 |
os.fdopen(fd[, mode[,bufsize]]) | 通过文件描述符fd打开文件,并返回对应的文件对象 |
os.closerange(fd_low, fd_high) | 关闭从fd_low(包含)到fd_high(不包含)范围的所有文件描述符 |
os.dup(fd) | 复制文件描述符 |
os.dup2(fd, fd2) | 将一个文件描述符fd复制到另一个文件描述符fd2中 |
os.ftruncate(fd, length) | 将fd对应的文件截断到length长度,因此此处传入的length参数不应该超过文件大小 |
os.remove(path) | 删除path对应的文件,如果path是一个文件夹,则抛出OSError错误。 |
os.link(src, dst) | 创建从src到dst的硬链接。硬链接是UNIX系统的概念,Windows中表示复制目标文件 |
os.symlink(src, dst) | 创建从src到dst的符号链接,对应与windows的快捷方式 |
八、使用tempfile模块生成临时文件和临时目录
常用函数:
● tempfile.TemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None):创建临时文件。该函数返回一个类文件对象,也就是支持文件I/O
● tempfile.NamedTemporaryFile(mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True):创建临时文件,生成临时文件在文件系统中有文件名。
● tempfile.SpooledTemporaryFile(max_size=0, mode='w+b', buffering=None, encoding=None, newline=None, suffix=None, prefix=None, dir=None):创建临时文件。当程序向该临时文件输出数据时,会先输出到内存中,直到超过max_size才会真正输出到物理磁盘中。
● tempfile.TemporaryDirectory(suffix=None, prefix=None, dir=None):生成临时目录。
● tempfile.gettempdir():获取系统的临时目录。
● tempfile.gettempdirb():与gettempdir()相同,只是该函数返回字节串。
● tempfile.gettempprefix():返回用于生成临时文件的前缀名。
● tempfile.gettempprefixb():与gettempprefix()相同,只是该函数返回字节串。
本章练习:
1. 有两个磁盘文件text1.txt和text2.txt ,各存放一行英文字母,要求把这两个文件中的信息合并(按字母顺序排列),然后输出到一个新文件text3.txt 中。
# 打开并读取第一个文件,将文件内容保存到变量text1
with open('text1.txt', 'r') as f1:
text1 = f1.read()
# 打开并读取第二个文件,将文件内容保存到变量text2
with open('text2.txt', 'r') as f2:
text2 = f2.read()
# 合并两个文件的内容,存入变量text3
text3 = (list(text1) + list(text2))
# 对文件内容进行排序
text3.sort()
# 创建文件text3.txt,将排序后的内容写入文件
with open('text3.txt', 'w+') as f3:
f3.write("".join(text3))
2. 提示用户不断地输入多行内容,程序自动将该内容保存到my.txt 文件中,直到用户输入exit为止。
from pathlib import Path
import os
# 使用while循环,提示用户输入,直到用户输入exit
while True:
user_input = input('请输入一行内容,结束请输入exit')
if user_input.lower() == 'exit':
break
else:
# 判断my.txt文件是否存在
my_file = Path('my.txt')
if my_file.exists():
# 如果文件存在则以追加方式打开文件
with open(my_file, 'a+') as f:
# 写入用户输入数据
f.write(user_input + os.linesep)
else:
# 如果文件不存在则以w+方式打开文件
with open(my_file, 'w+') as f:
# 写入用户输入数据
f.write(user_input + os.linesep)
3. 实现一个程序,该程序提示用户输入一个文件路径,程序读取这个可能包含手机号码的文本文件(该文件内容可能很大),要求程序能识别出该文本文件中所有的手机号码,并将这些手机号码保存到phone.txt 文件中。
from pathlib import Path
import re, sys, codecs, os
# 提示用户输入一个文件路径
u_input = input("请输入文件路径,使用绝对路径:")
# 使用用户输入路径创建Path对象
u_path = Path(u_input)
# 判断路径是否有效,是否为文件
if not u_path.exists() or not u_path.is_file():
# 提示用户输入错误,并退出
print('您输入的不是有效的文件路径')
sys.exit(0)
# 创建函数根据传入的文件对象,一次读取一行,对行内容进行匹配,将匹配到的
# 手机号码写入文件phone.txt
def read_file(f, wf):
while True:
line = f.readline()
# 如果没有读取到数据则退出循环
if not line:
break
# 手机号码匹配模式字符串
phone_pattern = '1[358][0-9]\d{8}|14[579]\d{8}|16[6]\d{8}|17[0135678]\d{8}|19[89]\d{8}'
# 对读取到的行数据进行模式匹配
phone_list = re.findall(phone_pattern, line)
# 如果匹配到数据则开始写入,如果没有匹配到则什么都不做
if phone_list:
# 遍历匹配到的手机号列表,将手机号码写入phone.txt
for x in phone_list:
wf.write(x + os.linesep)
# 关闭文件流
f.close()
with open('phone.txt', 'w+') as wf:
# 尝试使用gbk或utf-8两种字符集读取文件
try:
f = codecs.open(u_path, 'r', 'gbk', buffering=True)
# 调用函数读取并写入文件
read_file(f, wf)
except:
try:
f = codecs.open(u_path, 'r', 'utf-8', buffering=True)
read_file(f, wf)
except:
print('该文件不是有效的文本文件')
sys.exit(0)
4. 实现一个程序, 该程序提示用户输入一个目录, 程序递归读取该目录及其子目录下所有能识别的文本文件,要求程序能识别出所有文件中的所有手机号码,并将这些手机号码保存到phones.txt 文件中。
import codecs
import os
import re
import sys
from pathlib import Path
# 提示用户输入一个目录
u_input = input("请输入一个目录:").strip()
# 根据用户输入创建Path对象
u_dir = Path(u_input)
# 判断用户输入的是否是一个目录
if not u_dir.exists() or not u_dir.is_dir():
print('您输入的不是一个有效目录')
sys.exit(0)
'''
从文件对象f,一次读入一行,对读入的文件进行匹配
如果是手机号码,则写入phones.txt
'''
def read_write(f, wf):
while True:
line = f.readline()
# 如果没有读到数据,跳出循环
if not line:
break
# 匹配读到的内容中的手机号码,如果没有匹配到则开始下一次循环
pattern = '1[358][0-9]\d{8}|14[579]\d{8}|16[6]\d{8}|17[0135678]\d{8}|19[89]\d{8}'
phone_list = re.findall(pattern, line)
if phone_list:
# 循环列表,写入wf文件对象
for x in phone_list:
wf.write(x + os.linesep)
f.close()
with open('phones.txt', 'w+') as wf:
# 遍历用户输入目录下的所有.txt文件
for file in u_dir.glob("*.txt"):
try:
# 使用GBK编码打开文件
f = codecs.open(file, 'r', 'gbk', buffering=True)
read_write(f, wf)
except:
try:
# 使用utf-8编码打开文件
f = codecs.open(file, 'r', 'utf-8', buffering=True)
read_write(f, wf)
except:
print('打开文件 %s 失败' % file)
sys.exit(0)
5. 实现一个程序, 该程序提示用户运行该程序时输入一个路径。该程序会将该路径下(及其子目录下)的所有文件列出来。
from pathlib import Path
'''
判断传入的file对象是否是一个目录,如果是一个目录,则递归列出文件
'''
def list_file(file):
for f in file.iterdir():
if Path(f).is_dir():
list_file(f)
else:
print(f)
# 提示用户输入一个路径
u_input = input('请输入一个路径:').strip()
# 根据用户输入创建Path对象
u_dir = Path(u_input)
# 判断路径是否有效,是否是一个目录
if not u_dir.exists() or not u_dir.is_dir():
raise ValueError('输入的路径不存在或者不是一个目录')
list_file(u_dir)
6. 实现一个程序, 当用户运行该程序时, 提示用户输入一个路径。该程序会将该路径下的文件、文件夹的数量统计出来。
from pathlib import Path
# 提示用户输入一个路径
u_input = input('请输入一个路径:').strip()
# 根据用户输入创建Path对象
u_dir = Path(u_input)
# 判断用户输入路径是否是有效路径
if not u_dir.exists():
raise ValueError('您输入的路径不存在')
# 创建函数遍历用户输入的目录,计算目录和文件数目
def count_dir(path):
dir_count = file_count = 0
for f in path.iterdir():
if Path(f).is_dir():
dir_count += 1
else:
file_count += 1
return dir_count, file_count
dir_count, file_count = count_dir(u_dir)
print('%s 目录下有%d个文件' % (u_dir, file_count))
print('%s 目录下有%d个文件夹' % (u_dir, dir_count))
7. 编写仿Windows 记事本的小程序。
①使用tkinter实现简单记事本
from tkinter import *
from tkinter.filedialog import *
from tkinter.messagebox import *
import os
# 文件名变量
filename = ""
def author():
'''
显示作者信息
'''
showinfo(title="作者", message="ib-top.com")
def about():
'''
显示版权信息
'''
showinfo(title="版权信息", message="2019 @copyright www.ib-top.com")
def my_new():
'''
新建文本文件
'''
global top, filename, textpad
top.title("未命名文件")
filename = None
textpad.delete(1.0, END)
def my_open():
'''
打开文件
'''
global filename
filename = askopenfilename(defaultextension=".txt")
if filename == "":
filename = None
else:
top.title("记事本" + os.path.basename(filename))
textpad.delete(1.0, END)
f = open(filename, 'r')
textpad.insert(1.0, f.read())
f.close()
def my_save():
'''
保存文件
:return:
'''
global filename
try:
f = open(filename, 'w')
msg = textpad.get(1.0, END)
f.write(msg)
f.close()
except:
my_saveas()
def my_saveas():
'''
另存文件
'''
global filename
f = asksaveasfilename(initialfile="未命名.txt", defaultextension=".txt")
filename = f
fh = open(f, 'w')
msg = textpad.get(1.0, END)
fh.write(msg)
fh.close()
top.title("记事本" + os.path.basename(f))
def my_cut():
'''
剪切
'''
global textpad
textpad.event_generate("<>")
def my_copy():
'''
复制
'''
global textpad
textpad.event_generate("<>")
def my_paste():
'''
粘贴
'''
global textpad
textpad.event_generate("<>")
def my_undo():
'''
撤销
'''
global textpad
textpad.event_generate("<>")
def my_redo():
'''
重做
'''
global textpad
textpad.event_generate("<>")
def my_select_all():
'''
全选
'''
global textpad
textpad.tag_add("Sel", "1.0", "end")
def my_find():
'''
查找
'''
t = Toplevel(top)
t.title("查找")
t.geometry("260x60+200+2500")
t.transient(top)
Label(t, text="查找:").grid(row=0, column=0, sticky="e")
v = StringVar()
e = Entry(t, width=20, textvariable=v)
e.grid(row=0, column=1, padx=2, pady=2, sticky="we")
e.focus_set()
c = IntVar()
Checkbutton(t, text="不区分大小写", variable=c).grid(row=1, column=1, sticky='e')
Button(
t, text="查找所有",
command=lambda: my_search(v.get(), c.get(), textpad, t, e)).grid(
row=0, column=2, sticky="e" + "w", padx=2, pady=2)
def close_search():
'''
关闭查找窗口
:return:
'''
textpad.tag_remove("match", "1.0", END)
t.destroy()
t.protocol("WM_DELETE_WINDOW", close_search)
def my_popup(event):
'''
弹出菜单
:param event:
:return:
'''
editmenu.tk_popup(event.x_root, event.y_root)
def my_search(needle, cssnstv, textpad, t, e):
textpad.tag_remove("match", "1.0", END)
count = 0
if needle:
pos = "1.0"
while True:
pos = textpad.search(needle, pos, nocase=cssnstv, stopindex=END)
if not pos:
break
lastpos = pos + str(len(needle))
textpad.tag_add("match", pos, lastpos)
count += 1
pos = lastpos
textpad.tag_config('match', fg='yellow', bg='green')
e.focus_set()
t.title(str(count) + "个被匹配")
top = Tk()
top.title("记事本")
top.geometry("1000x600+100+50")
menubar = Menu(top)
# 文件功能
filemenu = Menu(top)
filemenu.add_command(label="新建", accelerator="Ctrl+N", command=my_new)
filemenu.add_command(label="打开", accelerator="Ctrl+O", command=my_open)
filemenu.add_command(label="保存", accelerator="Ctrl+S", command=my_save)
filemenu.add_command(label="另存为", accelerator="Ctrl+Shift+S", command=my_saveas)
# 将文件菜单加入菜单栏
menubar.add_cascade(label="文件", menu=filemenu)
# 编辑功能
editmenu = Menu(top)
editmenu.add_command(label="撤销", accelerator="Ctrl+Z", command=my_undo)
editmenu.add_command(label="重做", accelerator="Ctry+Y", command=my_redo)
editmenu.add_separator()
editmenu.add_command(label="剪切", accelerator="Ctrl+X", command=my_cut)
editmenu.add_command(label="复制", accelerator="Ctrl+C", command=my_copy)
editmenu.add_command(label="粘贴", accelerator="Ctrl+V", command=my_paste)
editmenu.add_separator()
editmenu.add_command(label="查找", accelerator="Ctrl+F", command=my_find)
editmenu.add_command(label="全选", accelerator="Ctrl+A", command=my_select_all)
# 将编辑菜单加入菜单栏
menubar.add_cascade(label="编辑", menu=editmenu)
# 关于功能
aboutmenu = Menu(top)
aboutmenu.add_command(label="作者", command=author)
aboutmenu.add_command(label="版权", command=about)
# 将关于菜单加入菜单栏
menubar.add_cascade(label="关于", menu=aboutmenu)
top['menu'] = menubar
shortcutbar = Frame(top, height=25, bg="light sea green")
shortcutbar.pack(expand=NO, fill=X)
Inlabe = Label(top, width=2, bg="antique white")
Inlabe.pack(side=LEFT, anchor='nw', fill=Y)
textpad = Text(top, undo=True)
textpad.pack(expand=YES, fill=BOTH)
scroll = Scrollbar(textpad)
textpad.config(yscrollcommand=scroll.set)
scroll.config(command=textpad.yview)
scroll.pack(side=RIGHT, fill=Y)
# 热键绑定
textpad.bind("", my_new)
textpad.bind("", my_new)
textpad.bind("", my_open)
textpad.bind("", my_open)
textpad.bind("", my_save)
textpad.bind("", my_save)
textpad.bind("", my_select_all)
textpad.bind("", my_select_all)
textpad.bind("", my_find)
textpad.bind("", my_find)
# textpad.bind("", my_cut)
# textpad.bind("", my_cut)
# textpad.bind("", my_undo)
# textpad.bind("", my_undo)
# textpad.bind("", my_cut)
# textpad.bind("", my_cut)
# textpad.bind("", my_redo)
# textpad.bind("", my_redo)
# textpad.bind("", my_copy)
# textpad.bind("", my_copy)
textpad.bind("", my_popup)
top.mainloop()
②使用wxPython实现简单记事本
# 引入wx包
import wx
import os
# 创建1个框架(frame),框架中包含1个可编辑文本框(text box)。
# 文本框用wx.TexCtrl来创建,默认情况下,文本框只能编辑1行文字,即不会自动换行。
# 将文本框放入panel中方便管理
# 利用wx.TE_MULTILINE参数来允许多行编辑
class MainWindow(wx.Frame):
"""
重写wx.Frame的__init__方法。
"""
def __init__(self):
# 文件对象
self.file = ""
self.content = []
self.count = 0
self.width = 700
self.height = 500
wx.Frame.__init__(self, None, -1, u"记事本", size=(400, 300))
self.panel = wx.Panel(self, -1)
self.text = wx.TextCtrl(
self.panel,
-1,
pos=(2, 2),
size=(self.width - 10, self.height - 50),
style=wx.TE_MULTILINE | wx.HSCROLL)
# 状态栏设置
self.statusbar = self.CreateStatusBar() # 窗口底部状态栏
self.statusbar.SetFieldsCount(3) # 将状态栏分隔为3个区域
self.statusbar.SetStatusWidths([-1, -2, -3]) # 将状态栏分隔比例为1:2:3
# 状态栏区域0文本信息
self.statusbar.SetStatusText("Area0!!!", 0)
# 状态栏区域1文本信息
self.statusbar.SetStatusText("Area1!!!", 1)
# 状态栏区域2文本信息
self.statusbar.SetStatusText("Area2!!!", 2)
# 设置文件菜单栏
menubar = wx.MenuBar()
filemenu = wx.Menu()
menubar.Append(filemenu, u'文件')
# 为文件菜单添加子菜单
# wx.ID_NEW等是wxWidgets提供的标准ID,如果有现成的标准ID,
# 最好使用标准ID,而不要自定义,这样可以让wxWidgets知道如何显示这个组件
menuOpen = filemenu.Append(wx.ID_OPEN, u"打开", u"打开文本文件")
menuSave = filemenu.Append(wx.ID_SAVE, u"保存", u"保存文件")
menuSaveas = filemenu.Append(wx.ID_SAVEAS, u"另存为", u"另存文件")
menuExit = filemenu.Append(wx.ID_EXIT, u"退出", u"退出应用程序")
# 设置编辑菜单
EditMenu = wx.Menu()
menubar.Append(EditMenu, u"编辑")
# 为编辑菜单添加子菜单
menuUndo = EditMenu.Append(wx.ID_UNDO, u"撤销", u"撤销编辑")
menuClear = EditMenu.Append(wx.ID_CLEAR, u"清空", u"清空编辑器")
menuCut = EditMenu.Append(wx.ID_CUT, u"剪切", u"剪切选中文本")
menuCopy = EditMenu.Append(wx.ID_COPY, u"复制", u"复制选中文本")
menuPaste = EditMenu.Append(wx.ID_PASTE, u"粘贴", u"粘贴剪贴板文本")
menuSelectAll = EditMenu.Append(wx.ID_SELECTALL, u"全选", u"选中全部文本")
# 创建快捷键
menu = wx.Menu()
ctrla = menu.Append(-1, "\tCtrl-A")
ctrlc = menu.Append(-1, "\tCtrl-C")
ctrlx = menu.Append(-1, "\tCtrl-X")
ctrlv = menu.Append(-1, "\tCtrl-V")
ctrls = menu.Append(-1, "\tCtrl-S")
# 添加快捷键
menubar.Append(menu, u'快捷键')
self.SetMenuBar(menubar)
# 绑定快捷键事件
self.Bind(wx.EVT_MENU, self.OnSelect, ctrla)
self.Bind(wx.EVT_MENU, self.OnCopy, ctrlc)
self.Bind(wx.EVT_MENU, self.OnCut, ctrlx)
self.Bind(wx.EVT_MENU, self.OnPaste, ctrlv)
self.Bind(wx.EVT_MENU, self.OnTSave, ctrls)
# 设置开始菜单events
self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
self.Bind(wx.EVT_MENU, self.OnSaveAll, menuSaveas)
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
# 设置编辑菜单events
self.Bind(wx.EVT_MENU, self.OnBack, menuUndo)
self.Bind(wx.EVT_MENU, self.OnClear, menuClear)
self.Bind(wx.EVT_MENU, self.OnCut, menuCut)
self.Bind(wx.EVT_MENU, self.OnCopy, menuCopy)
self.Bind(wx.EVT_MENU, self.OnPaste, menuPaste)
self.Bind(wx.EVT_MENU, self.OnSelect, menuSelectAll)
# 设置窗口大小重置events
self.Bind(wx.EVT_SIZE, self.OnResize)
# 设置应用程序窗口居中显示
self.Center()
# 打开文件
def OnOpen(self, event):
filterFile = "All files(*.*)|*.*"
# 创建文件打开对话框
opendialog = wx.FileDialog(self, u"选择文件", os.getcwd(), "", filterFile,
wx.FD_OPEN)
if opendialog.ShowModal() == wx.ID_OK:
self.file = opendialog.GetPath()
f = open(self.file)
self.text.write(f.read())
f.close()
opendialog.Destroy()
def OnTOpen(self, event):
filterFile = "All files(*.*)|*.*"
# 创建文件打开对话框
opendialog = wx.FileDialog(self, u"选择文件", os.getcwd(), "", filterFile,
wx.FD_OPEN)
if opendialog.ShowModal() == wx.ID_OK:
self.file = opendialog.GetPath()
f = open(self.file)
self.text.write(f.read())
f.close()
self.content.append(self.text.GetValue())
opendialog.Destroy()
# 保存文件
def OnSave(self, event):
filterFile = "All files(*.*)|*.*"
# 创建保存文件对话框
opendialog = wx.FileDialog(self, u"保存文件", os.getcwd(), "", filterFile,
wx.FD_SAVE)
if opendialog.ShowModal() == wx.ID_OK:
self.file = opendialog.GetPath()
self.text.SaveFile(self.file)
# 保存文件
def OnTSave(self, event):
if self.file == "":
filterFile = "All files(*.*)|*.*"
opendialog = wx.FileDialog(self, u"保存文件", os.getcwd(), "",
filterFile, wx.FD_SAVE)
if opendialog.ShowModal() == wx.ID_OK:
self.file = opendialog.GetPath()
self.text.SaveFile(self.file)
self.content.append(self.text.GetValue())
self.count = self.count + 1
else:
self.text.SaveFile(self.file)
self.content.append(self.text.GetValue())
self.count = self.count + 1
# 另存文件
def OnSaveAll(self, event):
pass
# 退出程序
def OnExit(self, event):
self.Close()
def OnTExit(self, event):
self.Close()
# 撤销编辑
def OnBack(self, event):
self.text.Undo()
def OnTBack(self, event):
try:
self.count = self.count - 1
self.text.SetValue(self.content[self.count])
except IndexError:
self.count = 0
# 重做
def OnTGo(self, event):
try:
self.count = self.count + 1
self.text.SetValue(self.content[self.count])
except IndexError:
self.count = len(self.content) - 1
# 新建
def OnTNew(self, event):
self.text.Clear()
def OnClear(self, event):
self.text.Clear()
def OnTClear(self, event):
self.text.Clear()
# 剪切
def OnCut(self, event):
self.text.Cut()
# 复制
def OnCopy(self, event):
self.text.Copy()
# 粘贴
def OnPaste(self, event):
self.text.Paste()
# 全选
def OnSelect(self, event):
self.text.SelectAll()
# 重置窗口大小
def OnResize(self, event):
newsize = self.GetSize()
# 这里需要注意一点,在重新设置wx.TextCtrl之前,需要先设置panel的尺寸
self.panel.SetSize(newsize)
width = newsize.GetWidth() - 10
height = newsize.GetHeight() - 50
self.text.SetSize(width, height)
self.text.Refresh()
def main():
app = wx.App(False)
myFrame = MainWindow()
myFrame.Show()
app.MainLoop()
if __name__ == '__main__':
main()
8. 编写一个命令行工具, 这个命令行工具就像Windows 提供的cmd 命令一样,可以执行各种常见的命令,如dir 、md 、copy 、move 等。
import os
import shutil
import sys
from pathlib import *
while True:
# resolve() 返回一个新的路径,这个新路径就是当前Path对象的绝对路径,如果是软链接则直接被解析
# absolute()也可以获取绝对路径,但是推荐使用reslove()
cmd = input('%s>' % Path('.').resolve()).strip()
# 判断用户输入,如果输入exit则退出
if cmd == 'exit':
sys.exit(0)
# 模拟dir命令
elif cmd.startswith('dir'):
# 如果用户输入以dir开头,则分解用户输入,提取出相应参数(默认以空格为分隔符)
params = cmd.split()
# 判断用户输入参数的数量
if len(params) == 1:
# 只输入了dir,则显示当前目录中的文件
for filename in os.listdir(r'.'):
print(filename)
elif len(params) == 2:
# 输入了2个参数,第二个参数应为路径
if Path(params[1]).exists() and Path(params[1]).is_dir():
# 打印用户输入路径下的文件名
for filename in os.listdir(params[1]):
print(filename)
else:
print('您输入的路径不存在,请重新输入')
break
else:
print('dir命令格式不正确,正确格式为: dir [路径]')
# 模拟cd命令
elif cmd.startswith('cd'):
params = cmd.split()
# 如果用户只输入了一个参数,则显示当前目录路径
if len(params) == 1:
# os.path.expanduser(path) #把path中包含的"~"和"~user"转换成用户目录
os.chdir(os.path.expanduser('~'))
elif len(params) == 2 and Path(params[1]).is_dir():
os.chdir(params[1])
else:
print('cd命令格式不正确,正确格式为:cd [路径]')
# 模拟md命令
elif cmd.startswith('md'):
params = cmd.split()
if len(params) < 2:
# md命令需要至少1个参数
print('md命令格式不正确,正确格式为:md <路径1> [路径2] ...')
else:
for i in range(1, len(params)):
os.mkdir(params[i])
# 模拟copy命令
elif cmd.startswith('copy'):
params = cmd.split()
# copy命令必须包含2个参数,第一个参数为要拷贝的文件,第二个参数为拷贝到哪个路径
if len(params) != 3 or (not Path(params[1]).is_file()) or (not Path(
params[2]).is_dir()):
print('copy命令格式不正确,正确格式为:copy <文件> <路径>')
else:
# shutil是对os中文件操作的补充,提供了--移动 复制 打包 压缩 解压等功能
shutil.copy(params[1], params[2])
# 模拟move命令
elif cmd.startswith('move'):
params = cmd.split()
# move命令必须包含2个参数,第一个参数为要移动的文件,第二个参数为移动到哪个路径
if len(params) != 3 or (not Path(params[1]).is_file()) or (not Path(
params[2]).is_dir()):
print('move命令格式不正确,正确格式为:move <文件> <路径>')
else:
shutil.move(params[1], params[2])
else:
print('无效命令')