文件操作和函数
Posted 龚旭1994
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件操作和函数相关的知识,希望对你有一定的参考价值。
一,文件的打开模式
打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作。
打开文件的模式有:
- r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】
- w,只写模式【不可读;不存在则创建;存在则清空内容】
- x, 只写模式【不可读;不存在则创建,存在则报错】
- a, 追加模式【可读; 不存在则创建;存在则只追加内容】
"+" 表示可以同时读写某个文件
- r+, 读写【可读,可写】
- w+,写读【可读,可写】
- x+ ,写读【可读,可写】
- a+, 写读【可读,可写】
"U"表示在读取时,可以将 \\r \\n \\r\\n自动转换成 \\n (与 r 或 r+ 模式同使用)
- rU
- r+U
"b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
- rb 或 r+b
- wb 或 w+b
- xb 或 w+b
- ab 或 a+b
以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码
flush原理:
- 文件操作是通过软件将文件从硬盘读到内存
- 写入文件的操作也都是存入内存缓冲区buffer(内存速度快于硬盘,如果写入文件的数据都从内存刷到硬盘,内存与硬盘的速度延迟会被无限放大,效率变低,所以要刷到硬盘的数据我们统一往内存的一小块空间即buffer中放,一段时间后操作系统会将buffer中数据一次性刷到硬盘)
- flush即,强制将写入的数据刷到硬盘
import sys,time for i in range(10): sys.stdout.write(\'#\') sys.stdout.flush() time.sleep(0.2) 或者 import time for i in range(10): print(\'#\',end=\'\',flush=True) time.sleep(0.2) else: print()
一: read(3):
1. 文件打开方式为文本模式时,代表读取3个字符
2. 文件打开方式为b模式时,代表读取3个字节
二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate
注意:
1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的
2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
with
为了避免打开文件后忘记关闭,可以通过管理上下文,即:
1 with open(\'hello.txt\',\'r\') as f: 2 ...
如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源。
open函数详解
f = open("aa",mode="r",encoding="utf-8")
open(file[, mode[, buffering[, encoding[, errors[, newline[, closefd=True]]]]]])
open函数有很多的参数,常用的是file,mode和encoding
file文件位置,需要加引号
mode文件打开模式,见下面3
buffering的可取值有0,1,>1三个,0代表buffer关闭(只适用于二进制模式),1代表line buffer(只适用于文本模式),>1表示初始化的buffer大小;
encoding表示的是返回的数据采用何种编码,一般采用utf8或者gbk;
errors的取值一般有strict,ignore,当取strict的时候,字符编码出现问题的时候,会报错,当取ignore的时候,编码出现问题,程序会忽略而过,继续执行下面的程序。
newline可以取的值有None, \\n, \\r, ”, ‘\\r\\n\',用于区分换行符,但是这个参数只对文本模式有效;
closefd的取值,是与传入的文件参数有关,默认情况下为True,传入的file参数为文件的文件名,取值为False的时候,file只能是文件描述符,什么是文件描述符,就是一个非负整数,在Unix内核的系统中,打开一个文件,便会返回一个文件描述符。
r或rt 默认模式,文本模式读 2 rb 二进制文件 3 4 w或wt 文本模式写,打开前文件存储被清空 5 wb 二进制写,文件存储同样被清空 6 7 a 追加模式,只能写在文件末尾 8 a+ 可读写模式,写只能写在文件末尾 9 10 w+ 可读写,与a+的区别是要清空文件内容 11 r+ 可读写,与a+的区别是可以写到文件任何位置
#定义名 = open("文件名","模式",指定打开字符集方式)
f.name #查看db文件名
f.tell() 显示文件中,当前 光标位置
f.read() 读全部 (read是读字符 其他都是字节),f.read(5)读取5个字符
f.readline() 读一行 读取成列表形式
f.wirte() 写入
f.close() 关闭
f.seek(10) 移动10个字节 #f.seek(0,2)光标移动到最后操作 (对字节操作,utf-8中,汉字代表3个字节
f.encoding 查看字符编码
f.writable() 是否以写模式打开, #True为真 False为假
f.readable() 是否以读模式打开, #True为真 False为假
f.flush() 强制刷新到硬盘 #一般用于打印实时日志,基本不用,会导致硬盘速度变慢
- truncate 截断(只能从头开始截)
- f.fineno 文件描述符
- readable 判断是否文件打开的模式是否可读(r模式)
- readall 读所有
- seekable 可寻(适用于文本文件)
新建一个文件:
open 打开文件
mode 显示文件的打开模式,默认是r
windows默认编码是gbk,所以需要转换成utf-8
read一次性读完文件里的所有内容
1 f=open("hello.txt",\'r\',encoding=\'utf-8\') 2 data=f.read() 3 print(data)
文件的修改的方式
模式一(弊端:占内存,优点:省硬盘空间)
1 f=open("hello.txt",\'r\',encoding=\'utf-8\') #定义变量f=打开hello.txt,模式:,encoding="utf-8" windows默认是gbk所以需要转换成utf-8 2 data=f.read() #read()一次性读取文件所有内容 3 data=data.replace("haha","xixixi") #定义变量data读取文件内容,replace将文件里的haha替换成xixixi 4 f.close() #关闭文件 5 f=open("hello.txt",\'r\',encoding=\'utf-8\') 6 data=f.write() #内存文件内容,写入到文件(原文件清空) 7 f.close()
模式二(弊端:占硬盘空间,优点省内存空间)
mport os with open(\'a.txt\',\'r\',encoding=\'utf-8\') as read_f,\\ open(\'.a.txt.swap\',\'w\',encoding=\'utf-8\') as write_f: for line in read_f: if line.startswith(\'hello\'): line=\'哈哈哈\\n\' write_f.write(line) os.remove(\'a.txt\') os.rename(\'.a.txt.swap\',\'a.txt\')
2个文件转列表,转字典,转成列表中的N个字典
#db文件格式 #aa #bb #cc #读取db文件生成列表 goods =[] for gn in open("goods","rt",encoding="utf-8"): goods.extend(gn.strip().split()) price =[] for en in open("price","rt",encoding="utf-8"): price.extend(en.strip().split()) print(price) #2个列表合并成字典 shop=dict(zip(goods,price)) print(shop) #字典转成列表的子集添加n个字典 test = [] for k, v in shop.items(): test.append({"name": k, "m": v}) print(test)
一个文件转成列表中的N个字典
f2 = open(\'product\', \'r\', encoding=\'utf-8\') product_data = f2.read() f2.close() v = product_data.split(\'\\n\') print(v) # 将列表转换成字典 lin = [] for i in v: v1 = i.split(\':\') print(v1) v1[1] = int(v1[1]) dic = {v1[0]:v1[1]} lin.append(dic) print(lin)
光标问题
cuisor读取光标地址, read读取文件全部内容, seek 把光标移动到某个字节后面 f.seek(10) 代表移动10个字节(utf-8中,汉字代表3个字节) 创建文件lyric,填写内容如下 123456testABCDE my name is guolm python执行命令: >>>f = open("lyric","r",encoding="utf-8") #encoding 指定读取文件类型的格式 >>>print(\'cuisor:\',f.tell()) #f.tell()显示当前文件内光标位置, cuisor: 0 >>>print(f.read()) #读取f变量中全部内容, 如果是print(f.readline()) 读取一行内容 123456testABCDE my name is guolm >>>print("--------------------------------------") >>>print(\'cuisor:\',f.tell()) #f.tell()再次执行,28是当前光标所在字符位置 cuisor: 33 >>>print(f.read()) #上次执行read()读取全部,本次读取文件从最后执行,所有没内容 >>>print("--------------------------------------") >>>f.seek(10) #f.seek(10) 代表移动10个字节后面, f.seek(0)移动到开头 (utf-8中,汉字代表3个字节) >>>print("cursor:",f.tell()) #因为上边操作,光标从10字节之后,执行命令 cursor: 10 >>>print(f.read(5)) #读取5字符 注:汉字代表一个字符,每行的结尾(\\n)也代表一个字符 ABCDE >>>f.close() #文件结束
函数
为什么要有函数:使用函数之模块化程序设计
不适用模块的缺点:
1,体系结构不清晰,可读性差
2,可扩展性差
3,程序冗长
在函数中函数分为两类:
内置函数
自定义函数
定义函数的三种形式:
无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
空函数:设计结构代码
如果没有实现定义函数。而直接引用,就相当于在引用一个不存在的变量名,所以,函数的使用一定要遵循:先定义后调用
定义函数都干了哪些事?
只检测语法,不执行代码
函数的调用 :先找到名字,根据名字调用代码
在python中函数分为两种:
内置函数:内置函数都会带返回值
def func(args): \'文档描述\' 函数体 return 返回值
定义函数相当于在定义一个变量(函数名就是变量名,函数值就是函数体)
函数的参数:
1 形参和实参定义
2 形参即变量名,实参即变量值,函数调用则将值绑定到名字上,函数调用结束,解除绑定
3 具体应用
位置参数:按照从左到右的顺序定义的参数
位置形参:必选参数
位置实参:按照位置给形参传值
关键字参数:按照key=value的形式定义实参
无需按照位置为形参传值
注意的问题:
1. 关键字实参必须在位置实参右面
2. 对同一个形参不能重复传值
默认参数:形参在定义时就已经为其赋值
可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
注意的问题:
1. 只在定义时赋值一次
2. 默认参数的定义应该在位置形参右面
3. 默认参数通常应该定义成不可变类型
函数的调用(1,先找到名字 2,根据名字调用代码)
函数调用的三种形式
语句形式:foo() 表达式形式“3*len(\'\'hello) 当中另外一个函数的参数:range(len(\'hello\'))
如何定义函数(函数名要能反映其意义)
def foo(): \'函数的文档注释\' 函数体 return 返回值
自定义函数:def定义函数关键字,任何形式都可以,先定义后使用
def func(): print("hello") func()
def func(): print("#" *6) func()
def my_max(x,y): res=x if x>y else y return res
def auth(): \'认证功能\' pass auth()
x, y = 50, 25 small = x if x < y else y #还可以嵌套使用,然当还可以更多层嵌套 a,b,c = 10,20,5 minValue = a if a < b and a < c else (b if b < a and b < c else c)
以上三种情况返回值都为None:
没有return return 什么都不写 return None
def foo(): print("from foo") x=1 return 1,[2,3],[4,5],{} #返回值可以是任意类型 res=foo() print(res)
def foo(x,y): print(x) print(y) foo(1,2)
foo()
详细的区分函数的参数分为五种:
def foo(x,y,z): #位置形参:必须传值 print(x,y,z) foo(1,2,3) #位置实参数:与形参一一对应
关键字参数需要注意的问题: 1:关键字实参必须在位置实参后面 foo(1,z=3,y=2) #正确 foo(x=1,2,y=3) #错误
def foo(x,y,z): print(x,y,z) foo(z=3,x=1,y=2)
def register(name,age,sex=\'male\'): #形参:默认参数 print(name,age,sex) register(\'aa\',age=18) register(\'bb\',22) register(\'cc\',33) register(\'dd\',44) register(\'哈哈\',20,\'female\')
默认参数需要注意的问题:
一:默认参数必须跟在非默认参数后
def register(sex=\'male\',name,age): #定义阶段就会报错 print(name,age,sex)
可变长参数:
针对实参在定义时长度不固定的情况,应该从形参的角度找到可以接收可变长实参的方案,这就是可变长参数(形参)
而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参也应该有两种解决方案,分别是*args,**kwargs
*位置参数
def foo(x,y,*args): #会把溢出的按位置定义的实参都接收,以元组的形式赋值给args def foo(x,y,*args): print(x,y) print(args) foo(1,2,3,4,5,5)
**关键字参数
def foo(x,y,**kwargs): #会把溢出的按位置定义的实参都接收,以字典的形式赋值给kwargs print(x,y) print(kwargs) foo(x=1,y=2,a=3,b=5,c=9)
def foo(name,age,*,sex,height): #*后定义的参数为命名关键字参数,这类参数,必须传值 print(name,age) print(sex) print(height) foo(\'haha\',22,height=\'gril\',sex=\'163\')
def foo(x,y,z): print(\'from foo\',x,y,z) def wrapper(*args,**kwargs): print(args) print(kwargs) foo(*args,**kwargs) wrapper(1,z=2,y=3)
以上是关于文件操作和函数的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段15——git命令操作一个完整流程
VSCode自定义代码片段15——git命令操作一个完整流程
我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情