05-2 目录文件处理

1,文件IO操作

函数说明
open打开
read读取
write写入
close关闭
readlne行读取
readlines多行读取

1.1 open方法

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None,
closefd=True, opener=None) 

打开一个文件,返回一个文件对象(流对象)和文件描述符。打开文件失败,则返回异常 基本使用:创建一个文件test,然后打开它,用完关闭

f = open("test") # file对象
# windows <_io.TextIOWrapper name='test' mode='r' encoding='cp936'> # linux <_io.TextIOWrapper name='test' mode='r' encoding='UTF-8'> 

print(f.read()) # 读取文件

f.close() # 关闭文件

文件操作中,最常用的操作就是读和写。

文件访问的模式有两种:文本模式和二进制模式。不同模式下,操作函数不尽相同,表现的结果也不一 样。

注: windows中使用codepage代码页,可以认为每一个代码页就是一张编码表。cp936等同于GBK。

1.2 open参数

1.2.1 file

打开或者要创建的文件名。如果不指定路径,默认是当前路径

1.2.2 mode模式

模式描述符意义
r缺省模式,只读打开
w只写打开
x创建并写入一个新文件
a只写打开,追加内容
b二进制模式
t缺省模式,文本模式
+读或写打开后,使用+来增加缺失的写或读的能力

模式对于IO操作来说,其实只有读和写两种:

  • 只读 r
  • 只写 w、x、a
  • 增加缺失能力 +

r 模式:

  • 只读打开文件,如果使用write方法,会抛异常
  • 如果文件不存在,抛出FileNotFoundError异常

w模式

  • 表示只写方式打开,如果读取则抛出异常
  • 如果文件不存在,则直接创建文件
  • 如果文件存在,则清空文件内容

x模式

  • 文件不存在,创建文件,并只写方式打开
  • 文件存在,抛出FileExistsError异常

a模式

  • 文件存在,只写打开,追加内容
  • 文件不存在,则创建后,只写打开,追加内容

wxa模式都可以产生新文件

  • w不管文件存在与否,都会生成全新内容的文件
  • a不管文件是否存在,都能在打开的文件尾部追加
  • x必须要求文件事先不存在,自己要造一个新文件

文本模式

  • 字符流,将文件的字节按照某种字符编码理解,按照字符操作。open的默认mode就是rt。

二进制模式

  • 字节流,将文件就按照字节理解,与字符编码无关。二进制模式操作时,字节操作使用bytes类型

+ 模式

  • 为r、w、a、x提供缺失的读或写功能,但是,获取文件对象依旧按照r、w、a、x自己的特征
  • +模式不能单独使用,可以认为它是为前面的模式字符做增强功能的。

1.2.3 encoding:编码,仅文本模式使用

None 表示使用缺省编码,依赖操作系统。windows、linux下测试如下代码

f = open('test1','w') 
f.write('啊') 
f.close()

windows下缺省GBK(0xB0A1),Linux下缺省UTF-8(0xE5 95 8A)

1.2.4 文件指针

mode=r,指针起始在0 mode=a,指针起始在EOF

f = open('o:/test.txt', 'wb+')
print(f)
f.write(b'abc')
print(f.tell())
f.close()
f = open('o:/test.txt', 'rt+') # windows下打开 
f.write('啊') # 从什么地方开始写几个字节? 
print(hex(ord('啊')), '啊'.encode(), '啊'.encode('gbk')) print(f.tell())
f.close()

1.3 read

read(size=-1)

  • size表示读取的多少个字符或字节;负数或者None表示读取到EOF
filename = 'o:/test.txt' 
f = open(filename, 'w+') 
f.write('测试')
f.close()

f = open(filename)
print(1, f.read(1)) # 按字符 
print(2, f.read(2)) 
print(3, f.read()) 
f.close()

f = open(filename, 'rb')
print(4, f.read(1)) # 按字节
print(5, f.read(2))
print(6, '测试'.encode('gbk'))
print(7, f.read())
f.close()

建议,使用文件对象时,一定要指定编码,而不是使用默认编码

1.4 wite

  • write(s),文本模式时,从当前指针处把字符串s写入到文件中并返回写入字符的个数;二进制时将 bytes写入文件并返回写入字节数
  • writelines(lines),将字符串列表写入文件
filename = 'o:/test.txt' 
f = open(filename, 'w+') 
lines = ['abc', '123\n', 'magedu'] # 需提供换行符
# for line in lines: 
#     f.write(line) 
f.writelines(lines) 
f.seek(0) # 回到开始 
print(f.read()) 
f.close()

1.5 close

flush并关闭文件对象。文件已经关闭,再次关闭没有任何效果。可以查看文件对象的closed属性,判断 是否关闭

2.上下文管理

文件对象这种打开资源并一定要关闭的对象,为了保证其打开后一定关闭,为其提供了上下文支持。

filename = 'o:/test.txt'
with open(filename) as f:
    print(1, f.closed) 
    print(f.write('abcd')) # r模式写入失败,抛异常

print(2, f.closed) # with中不管是否抛异常,with结束时都会保证关闭文件对象
with 文件对象 as 标识符: # 等同于 标识符 = 文件对象 
    pass # 标识符可以在内部使用

上下文管理:

  1. 使用with关键字,上下文管理针对的是with后的对象
  2. 使用with ... as 关键字
  3. 上下文管理的语句块并不会开启新的作用域

文件对象上下文管理

  1. 进入with时,with后的文件对象是被管理对象
  2. as子句后的标识符,指向with后的文件对象
  3. with语句块执行完的时候,会自动关闭文件对象
filename = 'o:/test.txt'
f = open(filename)
with f:
    print(1, f.closed) 
    print(f.write('abcd')) # r模式写入失败
print(2, f.closed) # with中不管是否抛异常,with结束时都会关闭文件对象
filename = 'o:/test.txt' f = open(filename)
with f as f2:
    print(f is f2) # True

2.1 文件的遍历

类似于日志文件,文件需要遍历,最常用的方式就是逐行遍历。

filename = 'o:/test.txt'
with open(filename, 'w') as f: 
    f.write('\n'.join(map(str, range(101, 120))))
with open(filename) as f:
    for line in f: # 文件对象时可迭代对象,逐行遍历 
        print(line.encode()) # 带换行符

3,路径操作

3.1 os.path模块

# os模块常用函数
from os import path

p = path.join('/etc', 'sysconfig', 'network') # 拼接 
print(type(p), p)
print(path.exists(p)) # 存在

print(path.split(p))  # 分割
print(path.dirname(p), path.basename(p)) # 路径和基名

print(path.abspath(''), path.abspath('.')) # 绝对路径

print(path.splitdrive('o:/temp/test')) # windows方法

# 打印父目录
p1 = path.abspath(__file__) print(p1)
while p1 != path.dirname(p1): 
    p1 = path.dirname(p1)
    print(p1)

os.path模块操作的都是字符串。

3.2 Path类

从3.4开始Python提供了pathlib模块,使用Path类操作目录更加方便。

3.2.1 初始化

p = Path() # 当前目录, Path()、Path('.')、Path('')
p = Path('a', 'b', 'c/d') # 当前目录下的a/b/c/d
p = Path('/etc', Path('sysconfig'), 'network/ifcfg') # 根下的etc目录

3.2.2 拼接

操作符/

  • Path对象 / Path对象
  • Path对象 / 字符串
  • 字符串 / Path对象

joinpath

  • joinpath(*other) 在当前Path路径上连接多个字符串返回新路径对象
from pathlib import Path

p = Path()
p = p / 'a'
p1 = 'b' / p
p2 = Path('c')
p3 = p2 / p1
print(p1, p2, p3)
print(p3.parts)
print(p3.joinpath('d', 'e/f', Path('g/h')))

3.2.3 分解

parts属性,会返回目录各部分的元组

p = Path('/a/b/c/d')
print(p.parts) # 最左边的/是根目录

3.2.4 父目录

p = Path('/magedu/mysql/install/mysql.tar.gz') 
print(p.parent)
for x in p.parents: # 可迭代对象
    print(x)

3.2.5 目录组成部分

name、stem、suffix、suffixes、with_suffix(suffix)、with_name(name)

  • name 目录的最后一个部分
  • suffix 目录中最后一个部分的扩展名
  • stem 目录最后一个部分,没有后缀
  • name = stem + suffix

suffixes 返回多个扩展名列表:

  • with_suffix(suffix) 有扩展名则替换,无则补充扩展名
  • with_name(name) 替换目录最后一个部分并返回一个新的路径
from pathlib import Path

p = Path('/magedu/mysql/install/mysql.tar.gz') print(p.parent)
print(p.name)
print(p.stem)
print(p.suffix)
print(p.suffixes)
print(p.with_name('redis')) print(p.with_name('redis').with_suffix('.zip'))

3.2.6 全局方法

  • cwd() 返回当前工作目录
  • home() 返回当前家目录
p = Path('/magedu/mysql/install/mysql.tar.gz') 
print(p.cwd(), Path.cwd())
print(p.home(), Path.home())

3.2.7 判断方法

  • exists() 目录或文件是否存在
  • is_dir() 是否是目录,目录存在返回True
  • is_file() 是否是普通文件,文件存在返回True
  • is_symlink() 是否是软链接
  • is_socket() 是否是socket文件
  • is_block_device() 是否是块设备
  • is_char_device() 是否是字符设备
  • is_absolute() 是否是绝对路径

注意:文件只有存在,才能知道它是什么类型文件

3.2.8 绝对路径

  • resolve() 非Windows,返回一个新的路径,这个新路径就是当前Path对象的绝对路径,如果是软 链接则直接被解析。
  • absolute() 获取绝对路径。

3.2.9 通配符

  • glob(pattern) 通配给定的模式,返回生成器对象
  • rglob(pattern) 通配给定的模式,递归目录,返回生成器对象
  • ? 代表一个字符
  • *表示任意个字符
  • [abc]或[a-z] 表示一个字符
list(p.glob('test*')) # 返回当前目录对象下的test开头的文件 
list(p.glob('**/*.py')) # 递归所有目录,等同rglob 
list(p.glob('**/*'))

g = p.rglob('*.py') # 生成器,递归
next(g)
list(p.rglob('*.???')) # 匹配扩展名为3个字符的文件 
list(p1.rglob('[a-z]*.???')) # 匹配字母开头的且扩展名是3个字符的文件

3.2.10 其他操作

  • rmdir() 删除空目录。没有提供判断目录为空的方法
  • touch(mode=0o666, exist_ok=True) 创建一个文件
  • as_uri() 将路径返回成URI,例如'file:///etc/passwd'
  • mkdir(mode=0o777, parents=False, exist_ok=False)
    • parents,是否创建父目录,True等同于mkdir -p。False时,父目录不存在,则抛出 FileNotFoundError
    • exist_ok参数,在3.5版本加入。False时,路径存在,抛出FileExistsError;True时,FileExistsError被忽略
  • iterdir() 迭代当前目录,不递归
from pathlib import Path

p = Path('o:/a/b/c/d') 
p.mkdir(parents=True, exist_ok=True) (p / 'test').touch()

for x in p.parents[len(p.parents) - 1].iterdir(): # 不支持负索引 
    if x.is_dir():
        print('dir =', x)
    elif x.is_file():
        print('file =', x)
    else:
        print('other =', x)

stat 相当于stat命令

lstat 使用方法同stat(),但如果是符号链接,则显示符号链接本身的文件信息

4 shutil模块

文件拷贝:使用打开2个文件对象,源文件读取内容,写入目标文件中来完成拷贝过程。但是这样丢失 stat数据信息(权限等),因为根本没有复制这些信息过去。 目录复制又怎么办呢?

Python提供了一个方便的库shutil(高级文件操作)。

4.1 copy 复制

  • copyfileobj(fsrc, fdst[, length])

    • 文件对象的复制,fsrc和fdst是open打开的文件对象,复制内容。fdst要求可写。
    • length 指定了表示buffer的大小;
  • copyfile(src, dst, *, follow_symlinks=True)

    • 复制文件内容,不含元数据。src、dst为文件的路径字符串
    • 本质上调用的就是copyfileobj,所以不带元数据二进制内容复制。
  • copymode(src, dst, *, follow_symlinks=True) 仅仅复制权限。

  • copystat(src, dst, *, follow_symlinks=True)

    • 复制元数据,stat包含权限
  • copy(src, dst, *, follow_symlinks=True)

    • 复制文件内容、权限和部分元数据,不包括创建时间和修改时间。 本质上调用的是: copyfile(src, dst, follow_symlinks=follow_symlinks) copymode(src, dst, follow_symlinks=follow_symlinks)
  • copy2 比copy多了复制全部元数据,但需要平台支持。

    • 本质上调用的是:

    1,copyfile(src, dst, follow_symlinks=follow_symlinks)

    2,copystat(src, dst, follow_symlinks=follow_symlinks)

    copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False)

递归复制目录。默认使用copy2,也就是带更多的元数据复制。

src、dst必须是目录,src必须存在,dst必须不存在

ignore = func ,提供一个callable(src, names) -> ignored_names。提供一个函数,它会被调用。src是源目录,names是os.listdir(src)的结果,就是列出src中的文件名,返回值是要被过滤的文件名的set 类型数据。

# o:/temp下有a、b目录
def ignore(src, names):
    ig = filter(lambda x: x.startswith('a'), names) # 忽略a开头的 
    return set(ig)
shutil.copytree('o:/temp','o:/tt/o',ignore=ignore)

4.2 rm删除

shutil.rmtree(path, ignore_errors=False, οnerrοr=None)

递归删除。如同rm -rf一样危险,慎用。

它不是原子操作,有可能删除错误,就会中断,已经删除的就删除了。

ignore_errors为true,忽略错误。当为False或者omitted时onerror生效。

onerror为callable,接受函数function、path和execinfo。

shutil.rmtree('O:/tmp') # 类似 rm -rf

4.3 move 移动

move(src, dst,copy_function=copy2)

递归移动文件、目录到目标,返回目标。

本身使用的是 os.rename方法。

如果不支持rename,如果是目录则copytree再删除源目录。

默认使用copy2方法。

shutil.move('o:/a', 'o:/aaa') 
os.rename('o:/t.txt','o:/temp/t') 
os.rename('test3','/tmp/py/test300')

shutil还有打包功能。生成tar并压缩。支持zip、gz、bz、xz。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
附录A 程序文件目录 "体系要素 "序号 "程序文件编号"程 序 文 件 名 称 " "4.1公正性 "1 "CX01-2018 "保证公正性的控制程序 " "4.2保密性 "2 "CX02-2018 "保守秘密的控制程序 " "5结构要求 "3 "CX03-2018 "各部门各类人员职责与权限程序 " " "4 "CX04-2018 "内务管理程序 " " "5 "CX05-2018 "现场检测校准工作的控制程序 " "6.2人员 "6 "CX06-2018 "人力资源管理的控制程序 " "6.3设施和环境条件"7 "CX07-2018 "设施和环境条件的控制程序 " "6.4设备 "8 "CX08-2018 "测量设备使用和维护的管理程序 " " "9 "CX09-2018 "测量标准装置的管理程序 " "6.5计量溯源性 "10 "CX10-2018 "计量溯源性的控制程序 " "6.6外部提供的产品"11 "CX11-2018 "外部产品和服务的控制程序 " "和服务 " " " " "7.1要求、标书和 "12 "CX12-2018 "要求、标书和合同评审的管理程序 " "合同评审 " " " " "7.2方法的选择、 "13 "CX13-2018 "检测和校准方法的验证和确认程序 " "验证和确认 " " " " " "14 "CX14-2018 "开展新项目的评审程序 " "7.3抽样 "/ "不允许抽样 " "7.4检测或校准物品"15 "CX15-2018 "检测和校准物品处置的管理程序 " "的处置 " " " " "7.5技术记录 "16 "CX16-2018 "记录的控制程序 " "7.6测量不确定度 "17 "CX17-2018 "测量不确定度和CMC评定的控制程序" "评定 " " " " "7.7确保结果有效性"18 "CX18-2018 "检测和校准结果有效性的控制程序 " "7.8 结果报告 "19 "CX19-2018 "证书和报告的编制和管理程序 " " "20 "CX20-2018 "印章和标识管理的控制程序 " "7.9 投诉 "21 "CX21-2018 "投诉的处理程序 " "7.10不符合工作 "22 "CX22-2018 "不符合工作的控制程序 " "7.11数据控制和 "23 "CX23-2018 "数据控制与信息管理程序 " "信息管理 " " " " "8.3管理体系文件 "24 "CX24-2018 "文件的控制程序 " "控制 " " " " "8.4记录控制 "/ "CX16-2018 "记录的控制程序 " "8.5应对风险和机遇"25 "CX25-2018 "应对风险和机遇的控制程序 " "的措施 " " " " " "26 "CX26-2018 "预防措施的控制程序 " "8.6改进 "27 "CX27-2018 "改进的控制程序 " "8.7纠正措施 "28 "CX28-2018 "纠正措施的控制程序 " "8.8内部审核 "29 "CX29-2018 "内部审核的控制程序 " "8.9管理评审 "30 "CX30-2018 "管理评审的控制程序 " ----------------------- 附录A--程序文件目录全文共1页,当前为第1页。
### 回答1: 要在 Windows 系统中删除一个目录下的文件,可以使用 `del` 命令。但是要注意,这个命令会删除所有符合条件的文件,所以还需要限制条件来保留某些文件。 如果要保留三天内的文件,可以使用 `forfiles` 命令来实现。这个命令可以根据文件的日期来执行操作。 如果要保留名字为 STAN04.LOG,STAN05.LOG,STAN06.LOG 的文件,可以使用通配符来实现。 综上,可以使用以下脚本来实现删除目录下的文件,但是三天内的文件和保留名字为 STAN04.LOG,STAN05.LOG,STAN06.LOG 的文件: ``` @echo off rem 保留三天内的文件 forfiles -p "C:\mydir" -s -m *.* -d -3 -c "cmd /c del @file" rem 保留 STAN04.LOG,STAN05.LOG,STAN06.LOG 这三个文件 del "C:\mydir\STAN??.LOG" ``` 注意: - 在上述脚本中,`C:\mydir` 是目录的路径,请根据实际情况修改。 - 在使用 `del` 命令时,请注意文件名中的通配符。 - 如果要在脚本中使用中文,需要在脚本的第一行添加 `chcp 65001` 命令,以便脚本正确处理中文。 ### 回答2: 编写一个bat脚本实现删除指定目录下的文件,但保留三天内的文件和名字为STAN04.LOG,STAN05.LOG,STAN06.LOG的文件。 以下是一个示例的bat脚本: ```bat @echo off setlocal enabledelayedexpansion set "dir_path=C:\目标目录" // 目标目录的路径 set "keep_days=3" // 保留的天数 for /f "usebackq delims=" %%d in (`dir /b "%dir_path%"`) do ( set "file_path=%dir_path%\%%d" set "file_datetime=%%~td" set "file_name=%%~nd" set "ext=%%~xd" if /i "!file_name!"=="STAN04" ( echo !file_name!!ext! is preserved. ) else if /i "!file_name!"=="STAN05" ( echo !file_name!!ext! is preserved. ) else if /i "!file_name!"=="STAN06" ( echo !file_name!!ext! is preserved. ) else ( set "today=!date:~0,10!" for /f "usebackq" %%t in ('powershell -Command "(get-date -Format yyyy-MM-dd)"') do set "today=%%t" set "file_date=!file_datetime:~0,10!" :: 计算日期差 powershell -Command "$date1=Get-Date '%today%'; $date2=Get-Date '%file_date%'; $diff=($date1-$date2).Days; $diff" >nul 2>nul if !errorlevel! gtr %keep_days% ( if exist "!file_path!" ( echo Removing !file_path! del /f /q "!file_path!" ) ) echo !file_path! is preserved. ) ) endlocal ``` 说明: 1. 将`dir_path`变量设置为目标目录的路径。 2. 将`keep_days`变量设置为要保留的天数。在脚本中我们保留三天内的文件。 3. 使用`for /f`命令遍历目标目录中的所有文件。 4. 对于名字为STAN04.LOG,STAN05.LOG和STAN06.LOG的文件,仅输出保留的提示信息。 5. 对于其他文件,使用powershell计算文件的日期与当前日期的差值,超过`keep_days`的文件将被删除。 ### 回答3: 编写一个.bat脚本来删除目录下的文件,但保留3天内的文件以及名字为STAN04.LOG,STAN05.LOG,STAN06.LOG的文件。 首先,我们需要获取当前日期和三天前日期的变量。使用以下命令来获取日期: ```batch @echo off setlocal EnableDelayedExpansion REM 获取当前日期 for /f "tokens=2 delims==" %%G in ('wmic os get localdatetime /value') do set "datetime=%%G" set "date=!datetime:~0,8!" REM 获取三天前的日期 for /f "tokens=1-3 delims=-" %%A in ("%date%") do ( set "year=%%A" set /a "month=1%%B-100" set /a "day=1%%C-100" ) set /a "day-=3" if %day% lss 1 ( set /a "month-=1" if !month! lss 1 ( set /a "year-=1" set "month=12" ) if !month! lss 10 set "month=0!month!" if !day! lss 10 set "day=0!day!" ) set "three_days_before=%year%-%month%-%day%" ``` 接下来,我们使用`for`循环遍历目录中的所有文件。对于非STAN04.LOG,STAN05.LOG和STAN06.LOG的文件,我们检查其最后修改日期是否早于三天前的日期,如果是则删除该文件。 ```batch REM 获取目录路径,将其替换为实际的目录路径 set "directory_path=C:\目录路径" REM 遍历目录中的文件 for %%F in ("%directory_path%\*.*") do ( if not "%%~nxF"=="STAN04.LOG" ( if not "%%~nxF"=="STAN05.LOG" ( if not "%%~nxF"=="STAN06.LOG" ( for /f "tokens=1-3 delims=-" %%A in ("%%~tF") do ( set "file_date=%%A-%%B-%%C" if !file_date! lss %three_days_before% ( echo 删除文件:"%%~F" del "%%~F" ) ) ) ) ) ) ``` 将以上代码保存为一个扩展名为.bat的文件,然后替换`directory_path`为你要操作的目录的实际路径。运行脚本后,它将删除三天前的所有文件,除非它们的文件名是STAN04.LOG,STAN05.LOG或STAN06.LOG。请注意,在删除文件之前请务必先备份重要的文件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值