文件操作和函数

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原理:

  1. 文件操作是通过软件将文件从硬盘读到内存
  2. 写入文件的操作也都是存入内存缓冲区buffer(内存速度快于硬盘,如果写入文件的数据都从内存刷到硬盘,内存与硬盘的速度延迟会被无限放大,效率变低,所以要刷到硬盘的数据我们统一往内存的一小块空间即buffer中放,一段时间后操作系统会将buffer中数据一次性刷到硬盘)
  3. 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() 
三元表达式
if写中间,条件成立写左边
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 
return 一个值,函数调用返回的结果就是这个值
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) #错误
关键字参数:key=value
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自定义代码片段——声明函数

VSCode自定义代码片段8——声明函数

VSCode自定义代码片段——git命令操作一个完整流程

VSCode自定义代码片段15——git命令操作一个完整流程

VSCode自定义代码片段15——git命令操作一个完整流程

我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情