目录文件处理
文件IO操作
函数 | 说明 |
---|---|
open | 打开 |
read | 读取 |
write | 写入 |
close | 关闭 |
readline | 多读取 |
readlines | 多行读取 |
1.open方法
open(file,mode=‘r’,buffering=1,encoding=None,error=None,newline=None,closefd=True,opener=None)
#
f = open('d:/python/test.txt') #打开一个文件
print (f.read()) #读取里面的内容
f.close()#关闭文件
文件操作中,最常用的就是读写,
文件访问的模式有两种, 一种是文本模式,一种是二进制模式,操作函数不尽相同,表现结果也不同.
windows使用codepage代码页,通俗易懂就是一页代码就是一个编码表,cp963等同于GBK.
1.open参数
1.file参数
打开或者想要创建的文件名,如果不指定路径那么就是当前路径
mode模式
模式描述字符 | 意义 |
---|---|
r | 缺省模式意思是只读 |
w | 只写打开 |
x | 创建并且写入一个新文件 |
a | 只写打开追加内容 |
b | 二进制模式 |
t | 缺省模式,文本模式 |
+ | 读或写打开后追加权限,用来增加缺失的读写能力 |
模式对于IO来说,只有读写
-
r 读
-
wxa 只写
-
+增加
r模式
只读模式,表示文件只是可读,如果写入数据会抛日常
如果文件不存在也会抛异常
w模式
表示只写模式,读取则会抛出异常
文件不存在直接创建文件
文件存在则清空文件内容
x模式
文件不存在直接创建文件
文件存在则抛出异常
a模式
文件存在,只写打开,尾部追加内容
文件不存在,创建文件打开只写,追加内容
wxa模式
w不管文件是否存在都会生成新的文件内容,
a尾部追加,不管文件存在不存在
x文件不存在则创建,所以必须文件不存在
文本模式t
字符流,将文件的字节按照某种字符编码理解,按照字符操作.open的默认mode就是t.
二进制模式b
字节流,将文件就按照字节理解,与字符编码无关,二进制模式操作时,字节操作使用bytes类型
+模式
为 r,a,w,x进行追加,补齐缺失的功能.
+模式不能单独使用,认为他是为已存在的字符模式赋能
2.encoding:编码仅文本使用
none表示缺省编码,依赖操作系统windows,linux测试如下代码
f = open('d:/python/test.txt','w')
f.write('啊')
f.close()
linux 默认UTF-8而window使用GBK
3.文件指针
mode = r 指针起始为0
mode = a 指针在末尾 EOF
f = open('d:/python/test.txt','wb+')
print (f)
f.write(b'abc')
print (f.tell())
f.close()
#理解 w+二进制模式,写入模式+二进制
f = open('d:/python/test.txt','rt+')
f.write('啊')
print (hex(ord('啊')),'啊'.encode,'啊'.encode('gbk'))
print (f.tell())
f.close()
#理解R读模式+t文本模式
这两个模式都是覆盖的,他的起始点都是0,相当于开头
理解a模式
f = open('d:/python/test.txt','ba+')
print (f)
f.write(b'abc')
print (f.tell())
f.close()
f = open('d:/python/test.txt','ta+')
f.write('啊')
print (hex(ord('啊')),'啊'.encode,'啊'.encode('gbk'))
print (f.tell())
f.close()
a模式是尾部追加,起始点是EOF就是默认,观察文档,发现r读模式和a的区别
而且看上方案例发现第一次写入的是二进制的abc,那么如果追加的话会不会出问题?
我再放入一段代码请分析.
f = open('d:/python/test.txt','ba+')
print (f)
f.write(b'abc')
print (f.tell())
f.close()
f = open('d:/python/test.txt','ta+')
f.write('啊')
print (hex(ord('啊')),'啊'.encode,'啊'.encode('gbk'))
print (f.tell())
f.close()
#请分析这段代码是否有什么问题?
#00 00 00 00 00 00
tell函数
tell()指定当前字节索引位置.
seek函数
seek(offset,whence=0)相对与某处进行偏移
文本模式
- seek(0) 、seek(100),相对于右偏移,不可左超界.
- seek(0,1),只能是偏移0, 原地踏步,无用操作
- seek(0,2),只能是偏移0,就是跳到EOF末尾.
字节模式
- seek(0)、seek(100),相对右偏移,不可超界
- seek(0,1) 、seek(-5,1)、seek(5,1),相对当前索引位置偏移,不能左超界
- seek(0,2)、seek(-5,2)、seek(5,2)相对EOF偏移,不能左超界
最常用的操作就是 seek(0),seek(0,2) 右偏移 和调到末尾
f = open('d:/python/test.txt','ta+')
f.write('啊')
print (hex(ord('啊')),'啊'.encode,'啊'.encode('gbk'))
print (f.tell())
print (f.seek(0,2))
f.close()
#-------------------------------------
f = open('d:/python/test.txt','ta+')
f.write('啊')
print (hex(ord('啊')),'啊'.encode,'啊'.encode('gbk'))
print (f.tell())
print (f.seek(0))
f.close()
2.read
读取字符,size=字符个数,附属或者none 表示EOF
filename = "d:/python/test.txt"
f = open(filename,'w+',encoding='gbk')
f.write("恭喜发财,红包拿来")
print (f.tell())
f.close()
f = open(filename)
print (1,f.read(1))
print (2,f.read(2))
print (3,f.read())
f.close()
f = open(filename,'wb+')
print (4,f.read(1))
print (5,f.read(2))
print (6,"恭喜发财,红包拿来".encode('gbk'))
print (7,f.read())
f.close()
请一定要指定编码类型,避免不必要的错误
3.write
write 文本模式时,从当前指针把字符串写入到文件中并且返回个数,二进制则是写入到字节中返回字节数.
writelines(lines),将字符串列表写入文件
filename = "d:/python/test.txt"
f = open("d:/python/test.txt",'w+',encoding="gbk")
lines = [ '123','456\n','\t',"恭喜发财" ]
f.writelines(lines) #插入后指针在哪? 是EOF还是0
# f.seek(0)
print (f.read())
f.close()
思考 上端代码的指针问题,当执行 writelines后指针在哪呢?如果直接read 会读出什么来?
4.close
关闭文件对象,首先先flush刷新然后再关闭,可以查看文件的closed属性是否关闭
filename = "d:/python/test.txt"
f = open("d:/python/test.txt",'w+',encoding="gbk")
lines = [ '123','456\n','\t',"恭喜发财" ]
f.writelines(lines) #插入后指针在哪?
f.seek(0)
print (f.read())
print (f.closed)
f.close()
print (f.closed)
如果为True则为关闭,如果为False则为未关闭
上下文管理
1.上下文管理
文件对象这种打开必须要关闭的对象,为了保证他打开之后就一定会关闭的这个要求,提出了上下文的管理.
filename = "d:/python/test.txt"
with open(filename) as f :
print (1,f.closed)
print (2,f.write("abcd"))
print (f.closed)
#这段代码 wirte 会报错,not writable 没有写入权限
针对这个with 可以理解为
with 文件对象 as 标识符: #你这里可以把文件对象 == 标识符,类似for i = 需要循环对象
pass #标识符可以在内部使用
上下文管理with
1.使用with关键字,with针对的是with后的对象.
2.使用with … as 关键字.
3.上下文管理的语句并不会新的作用域.
文件对象上下文管理
1.进入with时,with后的文件对象是被管理的对象.
2.as后的语句是标识符,指向with后的文件对象, 文件对象 == 标识符.
3.with语句执行完成的时候,会自动关闭文件对象.
filename = "d:/python/test.txt"
with open(filename) as f :
print (1,f.closed)
print (2,f.write("abcd"))
print (f.closed)
f = open(filename)
with f as f2 :
print (f is f2)
print (f == f2)
#是否为True?
2.文件的遍历
类似日志文件,文件需要遍历,时间复杂度O(n),最常用则是逐行遍历.
filename = "d:/python/test.txt"
with open(filename,'w+',encoding='gbk') as f :
f.write('\n'.join(map(str,(range(1,100)))))
with open(filename) as f :
for lins in f :
print (lins.encode('gbk'))
路径操作
1.os.path模块
从名称上看即为系统路径模块,
from os import path
p = path.join('/etc','sysconfig','network')
print (p,type(p))
#os.path 只针对str进行操作返回值也是str
print(path.exists(p)) #是否存在?
print(path.split(p)) #linux 分割
print (path.splitdrive('d:/python/test.txt')) #windows方法
print (path.dirname(p),path.basename(p)) #路径 和基名 可以理解为最后的文件名或者文件夹名称
print (path.abspath(''),path.abspath('.')) #路径 ''代表本路径 .也代表本路径
print ('*' * 20 )
p1 = path.abspath(__file__) #取当前绝对路径下的文件名称,即为test.py的绝对路径
print (p1)
while p1 != path.dirname(p1): #循环条件 p1绝对路径 不等于此文件的路径,如果等于则退出循环,
p1 = path.dirname(p1) #做了一个赋值,将路径,赋值到p1,
print (p1) #输出p1,至于为什么输出呈阶梯状可以理解以下dirname他每次取值都是要舍弃最后的基名的
#从此可以看出,os.path模块针对的都是str字符串类型.
2.path 类
python3.4 支持此pathlib的模块,使用path类操作目录
1.初始化
from pathlib import Path
p = Path() #当前路径
print (p)
p = Path('a','b','c','d') #初始化生成
print (p)
p = Path('/etc',Path('sysconfig'),'network/ifcfg.cfg') #拼接
print (p)
2.拼接
操作符 /
path 对象/ path 对象
path对象/字符串
字符串/path对象
joinpath(*other)
joinpath路径上连接多个字符返回一个新的路径对象.
from pathlib import Path
p = Path()
print (p)
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.分解
parts属性,会返回各个目录的元组
from pathlib import Path
p = Path('/a/b/c/d')
print (p.parts)
#会输出什么?
4.父目录
parents 父目录,基于最后一个文件的上一个路径
from pathlib import Path
p = Path('/usr/local/source/pkg/mysql_5_7.tar.gz')
print (p.parents)
for i in p.parents:
print (i)
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('/data/apk/mysql/mysql_5_7.tar.gz')
print (1,p.name) #目录最后一部分
print (2,p.suffix) #目录最后一部分的扩展名
print (3,p.suffixes) #最后拓展名多个
print (4,p.with_name('redis')) #替换最后一部分,全部替换
print (5,p.with_name('redis').with_suffix('.keep')) #替换最后一部分然后加入后缀
6.全局方法
cwd()返回当前工作目录
home() 返回当前家目录
from pathlib import Path
p = Path('/data/apk/mysql/mysql_5_7.tar.gz')
print (p.cwd(),p.home())
7.判断方法
exists()目录或者文件是否存在
is_dir() 是否是目录,目录存在则返回True
is_file() 是否为普通文件,文件存在返回True
is_symlink() 是否是软连接
is_socket() 是否为socket 连接文件.
is_block_device() 是否为块存储设备.
is_char_device()是否为字符设备
is_absolute() 是否为绝对路径
文件只有存在才可以判断文件属性
from pathlib import Path
p = Path('d:/python/test.txt')
print (p.cwd(),p.home())
print (p.exists())
print (p.is_dir())
print (p.is_file())
print (p.absolute())
print (p.is_block_device())
print (p.is_symlink())
print (p.is_socket())
print (p.is_char_device())
8.绝对路径
resolve() 非windows,返回一个新的路径,新路径基于当前path的绝对路径,如果是软连接则被直接解析.windows 下无效果
absolote() 获取绝对路径.
from pathlib import Path
p = Path('test.py')
print (p.resolve())
print (p.absolute())
9.其他操作
rmdir 删除空目录,没有提供判断方法
touch (mode=0o666,exist_ok=True) 创建一个文件
as_uri() 将路径返回成url
mkdir(mode = 0o777,parents=false,exist_ok=flase)
parents 即为mkdir -p 创建父目录,父目录不存在时抛出异常filenofoundError
exist_ok=false 路径存在抛异常,true 则忽略
iterdir()迭代当前目录
from pathlib import Path
p = Path('d:/python/a/b/c/d')
p.mkdir(parents=True,exist_ok=True)
(p / 'test').touch()
p1 = p.parents[len(p.parents) -3 ] #索引
print (p1)
for x in p.parents[len(p.parents) -1 ].iterdir(): #-1为目录索引
if x.is_dir():
print ('dir = ',x )
elif x.is_file():
print ('file = ',x)
else:
print ('other',x)
10.通配符
glob(pattern) 通配指定模式,返回生成器对象
rglob(pattern) 通配指定模式,递归目录,返回生成器对象.
?代表一个字符
*代表任意字符
[abc]或者[a-z]表示一个字符
from pathlib import Path
p = Path("d:/python")
l1 = list(p.glob("test"))
l2 = list(p.glob("*.py"))
l3 = list(p.glob("**/*.py"))
g = p.rglob('*.py')
#next(g)
l4 = list(p.rglob("*.???"))
l5 = list(p.rglob('[a-z]*.???'))
print (1,l1,sep='\n')
print (2,l2,sep='\n')
print (3,l3,sep='\n')
print (4,l4,sep='\n')
print (5,l5,sep='\n')
3.shuitl 模块
文件拷贝:使用两个文件对象,读取源文件内容,写入目标文件中完成拷贝.这样会都是stat数据信息元数据,因为不会复制着一些数据.
python提供了方便的shuitl模块.
copy复制
follow_symlinks 复制权限!!!
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)
复制元数据
copy(src,dst,*,follow_symlinks=True)
复制文件内容,权限和元数据不报考修改时间和创建时间
本质上调用copyfile 和copymode
copy2比copy多了元数据全部复制,需要平台支持
本质调用copyfile 和copystat
copytree(src,dst,symlinks=False,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False)
递归复制目录,使用copy2,也就是带更多的元数据进行复制,
src和dst必须是目录,src源必须存在,dst必须不存在
ignore = func ,提供一个callable(src,name) ->ignored_name,意思就是提供一个可调用的src源和名称,names就是os.listdir的结果,就是src的文件名,多个,返回值是要被过滤的文件名集合类型数据.
import shutil
def ignore(src, names):
ig = filter(lambda x: x, names)
return set(ig)
print (shutil.copytree('d:/python/test1','d:/python/test4',ignore=ignore))
删除 rm
shutil.rmtree(path,ignore_error=False,onerror=None)
递归删除,如果rm -rf 一样,危险慎用
他不是原子操作有可能误删,中断后已经删除文件不可恢复.
ignore_error = False 忽略报错 当false或者omttied时onerror
onerror为callable(可以调用对象),接受function(函数),path,execinfo.
shutil.rmtree('d:/python/test1')
移动 mv
move(src,dst,copy_function=copy2)
递归移动文件,目录到目标,返回目标
本身使用是os.rename方法(系统重命名)
如果不支持os.rename,则使用copytree在删除目录
默认使用copy2方法
import shutil
print (shutil.move('d:/python/test1','d:/python/test2'))
print (os.rename('d:/python/test2','d:/python/test3'))
print (os.rename('d:/python/test3','d:/python/test4'))
ake_archive(base_name, format, root_dir=None, base_dir=None,owner=None, group=None, logger=No
* 参数详解
* base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
* format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
* root_dir: 要压缩的文件夹路径(默认当前目录)
* owner: 用户,默认当前用户
* group: 组,默认当前组
* logger: 用于记录日志,通常是logging.Logger对象
* 案例1:将 /data下的文件打包放置当前程序目录
import shutil
shutil.make_archive("d:/python/test10",'gztar',root_dir='d:/python/')
练习此文档大概需要练习的代码
filename = "d:/python/test.txt"
with open(filename,'w+',encoding='gbk') as f :
f.write('\n'.join(map(str,(range(1,100)))))
with open(filename) as f :
for lins in f :
print (lins.encode('gbk'))
filename = "d:/python/test.txt"
with open(filename,'w') as f :
print (1,f.closed)
print (2,f.write("abcd"))
print (f.closed)
f = open(filename)
with f as f2 :
print (f is f2)
print (f == f2)
from os import path
p = path.join('\etc','sysconfig','network','ifconfig.cfg')
print (p,type(p))
print(path.exists(p)) #是否存在?
print(path.split(p)) #linux 分割
print (path.splitdrive('d:/python/test.txt')) #windows方法
print (path.dirname(p),path.basename(p)) #路径 和基名 可以理解为最后的文件名或者文件夹名称
print (path.abspath(''),path.abspath('.')) #路径 ''代表本路径 .也代表本路径
print ('*' * 20 )
p1 = path.abspath(__file__) #取当前绝对路径下的文件名称,即为test.py的绝对路径
print (p1)
while p1 != path.dirname(p1): #循环条件 p1绝对路径 不等于此文件的路径,如果等于则退出循环,
p1 = path.dirname(p1) #做了一个赋值,将路径,赋值到p1,
print (p1) #输出p1,至于为什么输出呈阶梯状可以理解以下dirname他每次取值都是要舍弃最后的基名的
from pathlib import Path
p = Path()
print (p)
p = Path('a','b','c','d')
print (p)
p = Path('/etc',Path('sysconfig'),'network/ifcfg.cfg')
print (p)
from pathlib import Path
p = Path()
print (p)
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')))
from pathlib import Path
p = Path('/a/b/c/d')
print (p.parts)
from pathlib import Path
p = Path('/usr/local/source/pkg/mysql_5_7.tar.gz')
print (p.parents)
for i in p.parents:
print (i)
from pathlib import Path
p = Path('/data/apk/mysql/mysql_5_7.tar.gz')
print (1,p.name) #目录最后一部分
print (2,p.suffix) #目录最后一部分的扩展名
print (3,p.suffixes) #最后拓展名多个
print (4,p.with_name('redis')) #替换最后一部分,全部替换
print (5,p.with_name('redis').with_suffix('.keep')) #替换最后一部分然后加入后缀
from pathlib import Path
p = Path('d:/python/test.txt')
print (p.cwd(),p.home())
print (p.exists())
print (p.is_dir())
print (p.is_file())
print (p.absolute())
print (p.is_block_device())
print (p.is_symlink())
print (p.is_socket())
print (p.is_char_device())
from pathlib import Path
p = Path('test.py')
print (p.resolve())
print (p.absolute())
from pathlib import Path
p = Path('d:/python/a/b/c/d')
p.mkdir(parents=True,exist_ok=True)
(p / 'test').touch()
p1 = p.parents[len(p.parents) -3 ]
print (p1)
for x in p.parents[len(p.parents) -1 ].iterdir(): #-1为目录索引
if x.is_dir():
print ('dir = ',x )
elif x.is_file():
print ('file = ',x)
else:
print ('other',x)
from pathlib import Path
p = Path("d:/python")
l1 = list(p.glob("test"))
l2 = list(p.glob("*.py"))
l3 = list(p.glob("**/*.py"))
g = p.rglob('*.py')
#next(g)
l4 = list(p.rglob("*.???"))
l5 = list(p.rglob('[a-z]*.???'))
print (1,l1,sep='\n')
print (2,l2,sep='\n')
print (3,l3,sep='\n')
print (4,l4,sep='\n')
print (5,l5,sep='\n')
import os
import shutil
def ignore(src, names):
ig = filter(lambda x: x, names)
return set(ig)
print (shutil.copytree('d:/python/test1','d:/python/test4',ignore=ignore))
import shutil
print (shutil.move('d:/python/test2.tar.gz','d:/python/test2.zip'))
print (os.rename('d:/python/test2','d:/python/test3'))
print (os.rename('d:/python/test3','d:/python/test4'))
shutil.make_archive("d:/python/test10",'gztar',root_dir='d:/python/')