当前位置:   article > 正文

Python 自动化(三)文件读写操作与函数_python封装文件的读写函数

python封装文件的读写函数

一  文件读写操作

Linux 系统中万物皆文件,所以我们不可避免的要和文件打交道,我们会常常对文件进行读和写的操作。例如:

  1. cat /etc/password   # 读文件
  2. vim /etc/password   # 读写文件
  3. echo test > /tmp/abc.txt   # 覆盖写文件
  4. echo text >> /tmp/abc.txt  # 追加写文件

而以上内容我们都是对文本文件进行读写,计算机中也存在对二进制文件的读写操作,那用 Python 如何实现呢?

1. 文件的打开方法—open 内建函数

不管是读文件还是写文件,我们第一步都是要将文件打开。

作为打开文件之门的“钥匙”,内建函数 open() 提供了初始化输入/输出(I/O)操作的通用接口,成功打开文件后时候会返回一个文件对象,否则引发一个错误。

(1)基本语法

file_object = open(file_name,mode='r')

要以任何方式使用文件——哪怕仅仅是打印其内容,都得先打开打文件,这样才能访问它。

(2)参数介绍

file_name:表示我们要打开文件的路径

mode:以怎样的方式打开文件

文件模式操 作
r以读方式打开(文件不存在则报错)
w以写方式打开(文件存在则清空,不存在则创建)
a以追加模式打开
b以二进制模式打开

file_object:文件操作对象,我们后续对文件的所有读写操作都需要通过这个对象,而不是直接操作文件中的数据。

2. 文件读操作

要使用文本文件中的信息,首先需要将信息读取到内存中。为此,我们可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取。

(1)read 方法 —— 读取文件

  • open 函数的第一个参数是要打开的文件名(文件名区分大小写)

    • 如果文件 存在,返回 文件操作对象

    • 如果文件 不存在,会 抛出异常

  • read 方法可以一次性 读入返回 文件的 所有内容

  • close 方法负责 关闭文件

    • 如果 忘记关闭文件会造成系统资源消耗,而且会影响到后续对文件的访问

  • 注意read 方法执行后,会把 文件指针 移动到 文件的末尾

  1. # 1.打开文件
  2. fr = open("/etc/hosts", mode="r")  # r: read
  3. # 2.读取文件
  4. print(fr.read(5))  # 读取前5个字符
  5. print(fr.read(3))  # 接着向后读3个字符
  6. print(fr.read())   # 读取文件剩余的所有内容
  7. print(fr.read())   # 什么都读取不到,因为指针已经在末尾了
  8. # 3.关闭资源
  9. fr.close()

(2)文件指针

  • 文件指针 标记 从哪个位置开始读取数据

  • 第一次打开 文件时,通常 文件指针会指向文件的开始位置

  • 当执行了 read 方法后,文件指针 会移动到 读取内容的末尾

    • 默认情况下会移动到 文件末尾

  • 重新打开文件时,文件指针 重新指向文件的最 开始位置

图例

 思考

  • 如果执行了一次 read 方法,读取了所有内容,那么再次调用 read 方法,还能够获得到内容吗?

答案

  • 不能,因为第一次读取之后,文件指针移动到了文件末尾,再次调用不会读取到任何的内容

(3)readline 方法 —— 按行读取

  • read 方法默认会把文件的 所有内容 一次性读取到内存

  • 如果文件太大,对内存的占用会非常严重

  • readline 方法可以一次读取一行内容

  • 方法执行后,会把 文件指针 移动到下一行,准备再次读取

  1. # 1.打开文件
  2. fr1 = open("/etc/passwd", mode="r")  # r:read
  3. # 2.读取文件
  4. print(fr1.readline(), end="")  # 读取第一行数据
  5. print(fr1.readline(), end="")  # 读取第二行数据
  6. # 3.关闭资源
  7. fr1.close()
案例1:读取大文件的正确姿势
  1. # 1.打开文件
  2. fr = open("/etc/passwd", mode="r")
  3. # 2.读取文件
  4. while True:  # 死循环
  5.    data = fr.readline()  # 某一行数据
  6.    if len(data) == 0:  # 文件读取完毕,终止循环
  7.        break
  8.    print("data:", data, end="")
  9. # 3.关闭资源
  10. fr.close()

(4)readlines 方法

readlines()方法读取所有(剩余的)行然后把它们作为一个 字符串列表 返回

图例

  • 如果需要逐行处理文件,可以结合 for 循环迭代文件

  • 迭代文件的方法与处理其他序列类型的数据类似

  1. # 1.打开文件
  2. fr2 = open("/etc/hosts", mode="r")
  3. # 2.读取文件
  4. # 和for连用
  5. # data = fr2.readlines()
  6. # print("data:", data)
  7. # print(data[0]) # 第一行
  8. # print(data[1]) # 第二行
  9. for item in fr2:  # 相当于:for item in fr2.readlines():
  10.    print(item, end="")
  11. # 3.关闭资源
  12. fr2.close()

图列:

 二  文件写操作

1. write 方法 —— 写文件

  • write() 内建方法功能与 read()readline() 相反

    • 它把含有 文本数据二进制数据 的内容写入到文件中去

2. writelines 方法

  • readlines() 一样,writelines() 方法是针对 列表 的操作

  • 它接受一个 字符串列表 作为参数,将他们写入文件

  • 行结束符并不会被自动加入,所以如果需要的话,必须再调用 writelines() 前给每行结尾加上行结束符

案列2:write方法

  1. # 1.打开文件
  2. fw = open("/opt/dc.txt", mode="w")  # w: write
  3. # 2.写文件
  4. fw.write("hello world\n")
  5. fw.write("you are my baby girl~\n")
  6. # 3.关闭资源
  7. fw.close()
案例 3:writelines方法
  1. list01 = ["hello\n", "world\n", "nfx\n"]
  2. # 1.打开文件
  3. fw1 = open("/opt/tc.txt", mode="w")
  4. # 2.写文件
  5. fw1.writelines(list01)
  6. # 3.关闭资源
  7. fw1.close()
  8. # hello
  9. # world
  10. # nfx

图例:

 3. with 子句

  • with语句 是用来简化代码的

  • 在将打开文件的操作放在 with 语句中,代码块结束后,文件将自动关闭

  • 读写文件的逻辑没有变化,变得只是 写法

案例 4:with

  1. with open('/tmp/passwd', mode="r") as f:
  2.    # 文件的读写操作
  3.    # ......

练习与方案

  1. # 模拟 cp 操作
  2. # 1. 创建 cp.py 文件
  3. # 2. 将 /usr/bin/ls "拷贝"/tmp 目录下
  4. # 3. 不要修改原始文件
  5. fr = open("/usr/bin/ls", mode="rb") # rb:读取二进制
  6. fw = open("/tmp/myls",mode="wb") # wb:写二进制
  7. while True:
  8. data = fr.read(4096) # 4096字节 = 4k
  9. if len(data) == 0: # 文件读取完毕,终止循环
  10. break
  11. fw.write(data) # 将读到的数据写入文件
  12. fr.close()
  13. fw.close()

三  函数

1. 快速体验

  • 所谓函数,就是把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用

  • 函数的使用包含两个步骤:

    1. 定义函数 —— 封装 独立的功能

    2. 调用函数 —— 享受 封装 的成果

案例:洗衣服

  1. # 早上洗衣服
  2. print("打水")
  3. print("洗衣服")
  4. print("甩干")
  5. # 中午洗衣服
  6. print("打水")
  7. print("洗衣服")
  8. print("甩干")
  9. # 晚上洗衣服
  10. print("打水")
  11. print("洗衣服")
  12. print("甩干")

发现了问题:我们将有独立功能的代码封装成一个函数

  1. def washing_machine(): # 洗衣机可以帮我们完成
  2. print("打水")
  3. print("洗衣服")
  4. print("甩干")
  5. # 优化后代码
  6. # 早上洗衣服
  7. washing_machine() # 打开洗衣机开关
  8. # 中午洗衣服
  9. washing_machine() # 打开洗衣机开关
  10. # 晚上洗衣服
  11. washing_machine() # 打开洗衣机开关

2. 函数的创建与调用

(1)创建函数

函数用 def 语句创建,语法如下:

  1. def 函数名(参数列表): # 具体情况具体对待,参数可有可无
  2. """函数说明文档字符串"""
  3. 函数封装的代码
  4. ……

标题行由 def 关键字,函数的名字,以及参数的集合(如果有的话)组成

def 子句的剩余部分包括了一个可选的文档字串,和必需的函数体

函数名称 的命名应该 符合 标识符的命名规则

  • 可以由 字母下划线数字 组成

  • 不能以数字开头

  • 不能与关键字重名

  1. def washing_machine(): # 洗衣机可以帮我们完成
  2. print("打水")
  3. print("洗衣服")
  4. print("甩干")

(2)调用函数

使用一对圆括号 () 调用函数,如果没有圆括号,只是对函数的引用

任何输入的参数都必须放置在括号中

图例:

(3)案例:加洗衣粉

  1. def washing_machine(): # 洗衣机可以帮我们完成
  2. print("打水")
  3. print("加洗衣粉!!!")
  4. print("洗衣服")
  5. print("甩干")
  6. # 早上洗衣服
  7. washing_machine()
  8. # 中午洗衣服
  9. washing_machine()
  10. # 晚上洗衣服
  11. washing_machine()

(4)总结

  • 定义好函数之后,只表示这个函数封装了一段代码而已

  • 如果不主动调用函数,函数是不会主动执行的

(5)思考

  • 能否将 函数调用 放在 函数定义 的上方?

    • 不能!

    • 因为在 使用函数名 调用函数之前,必须要保证 Python 已经知道函数的存在

    • 否则控制台会提示 NameError: name '函数名' is not defined (名称错误:这个名字没有被定义)

3. 函数的参数

(1)形参和实参

  • 形参定义 函数时,小括号中的参数,是用来接收参数用的,在函数内部 作为变量使用

  • 实参调用 函数时,小括号中的参数,是用来把数据传递到 函数内部 用的

(2)问题

当我们想洗其他的东西,要手动改方法内部的代码:

  1. def washing_machine(): # 洗衣机可以帮我们完成
  2. print("打水")
  3. print("加洗衣粉!!!")
  4. print("洗床单") # 洗被套
  5. print("甩干")

在函数内部有一定的变化的值:

  1. def washing_machine(): # 洗衣机可以帮我们完成
  2. print("打水")
  3. print("加洗衣粉!!!")
  4. print("洗衣服")
  5. print("甩干")
  6. washing_machine()
  7. def washing_machine(): # 洗衣机可以帮我们完成
  8. print("打水")
  9. print("加洗衣粉!!!")
  10. print("洗床单")
  11. print("甩干")
  12. washing_machine()
  13. ......

思考一下存在什么问题

函数只能处理 固定 的数据

如何解决?

  • 如果能够把需要处理的数据,在调用函数时,传递到函数内部就好了!

(3)传递参数

  • 在函数名的后面的小括号内部填写 参数

  • 多个参数之间使用 , 分隔

  • 调用函数时,实参的个数需要与形参个数一致,实参将依次传递给形参

  1. def washing_machine(something): # 洗衣机可以帮我们完成
  2. print("打水")
  3. print("加洗衣粉!!!")
  4. print("洗" + something)
  5. print("甩干")
  6. # 洗衣服
  7. washing_machine("衣服")
  8. # 洗床单
  9. washing_machine("床单")

图例

作用

  • 函数,把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用

  • 函数的参数,增加函数的 通用性,针对 相同的数据处理逻辑,能够 适应更多的数据

    1. 在函数 内部,把参数当做 变量 使用,进行需要的数据处理

    2. 函数调用时,按照函数定义的参数顺序,把 希望在函数内部处理的数据通过参数 传递

位置参数

shell 脚本类似,程序名以及参数都以位置参数的方式传递给 python 程序,使用 sys 模块的 argv 列表接收

图例:

 (4)默认参数

默认参数就是声明了 默认值 的参数,因为给参数赋予了默认值,所以在函数调用时,不向该参数传入值也是允许的

1.如果没有手动给形参赋值,那么就用默认值
2.传递的实际参数优先级比默认参数要高
3.定义函数时,有默认值的参数一定放在没有默认值参数的后面

(5)案列;定义一个函数,计算两个数的和  num01  num02

  1. def get_sum(num01, num02=100):
  2. print(num01+num02)
  3. get_sum(50) # num01 = 50 num02 = 100
  4. get_sum(10, 20) # num01 = 10 num02 = 20
  5. get_sum(1, 2) # num01 = 1 num02 = 2
  6. def get_sum2(num01=30, num02=40):
  7. print(num01+num02)
  8. get_sum2() # num01=30 num02=40
  9. # def get_sum1(num01=100, num02): 报错
  10. # print(num01+num02)

4. 函数的返回值

  • 在程序开发中,有时候,会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理

  • 返回值 是函数 完成工作后,最后 给调用者的 一个结果

  • 在函数中使用 return 关键字可以返回结果

  • 调用函数一方,可以 使用变量接收 函数的返回结果

注意:return 表示返回,表示方法执行结束,后续的代码都不会被执行

(1)案例:取钱和查余额

  1. # 查余额: 看,不带走,不能买东西
  2. # 如果内部没有return语句,那么会默认返回None: return None
  3. def chaxun():
  4. print(100)
  5. # return None
  6. money1 = chaxun()
  7. print("我取了:", money1) # 我取了: None
  8. # 取钱: 将钱放自己兜里带走,能买东西
  9. # return后跟的数据,叫函数的返回值
  10. def quqian():
  11. return 100 # 将100放自己兜里带走
  12. money = quqian() # 调用quqian, 将100赋值给变量money
  13. print("我取了:", money) # 我取了: 100
  14. money -= 5
  15. print("我买了1个冰淇凌,花了5元,还剩", money)

图例说明

(2)没有 return

如果方法内部没有 return 语句,那么会默认返回 None,即 return None

(3)练习 3:斐波那契数列函数

斐波那契数列函数

  • 将斐波那契数列代码改为函数

  • 数列长度由用户指定

  • 要求把结果用 return 返回

版本一:方法内部直接打印

  1. def gen_fib():
  2. fib = [0, 1] # 定义列表,指定斐波那契数列的初始两个值
  3. n = int(input('长度: ')) # 定义变量n, 此变量为用户要看到的列表fib中的元素个数
  4. for i in range(n - 2):
  5. fib.append(fib[-1] + fib[-2])
  6. print(fib) # 打印列表fib
  7. # 调用两次函数gen_fib()
  8. gen_fib()
  9. gen_fib()

版本二:带返回值

  1. def gen_fib():
  2. fib = [0, 1]
  3. n = int(input('长度: '))
  4. for i in range(n - 2):
  5. fib.append(fib[-1] + fib[-2])
  6. return fib # 返回最后生成的列表fib
  7. # 调用函数gen_fib()
  8. print(gen_fib())

版本三:带参数

  1. def gen_fib(n):
  2. fib = [0, 1]
  3. for i in range(n - 2):
  4. fib.append(fib[-1] + fib[-2])
  5. return fib # 返回最后生成的列表fib
  6. # 定义列表nlist, 将要产生的斐波那契数列的长度,作为列表nlist的元素
  7. nlist = [10, 8, 6]
  8. # 使用for循环,传递实参(nlist中的元素)给函数gen_fib(n),得到三组斐波那契数列
  9. for i in nlist:
  10. print(gen_fib(i))

(4)练习4:复制文件函数

  • 修改文件练习中的拷贝程序

    • 将程序改为函数的形式

    • 源文件和目标文件要求通过参数进行传递

    • 实参要求来自于命令行

版本1:

  1. # 定义函数copy(),实现指定单个文件拷贝的功能
  2. def copy():
  3. src_name = '/usr/bin/ls'
  4. dst_name = '/tmp/list3'
  5. # 以只读字节的方式打开源文件,fr
  6. # 以写入字节的方式打开源文件,fw
  7. fr = open(src_name, mode='rb')
  8. fw = open(dst_name, mode='wb')
  9. while True:
  10. data = fr.read(4096)
  11. if len(data) == 0:
  12. break
  13. fw.write(data)
  14. fr.close()
  15. fw.close()
  16. copy() # 调用拷贝文件的函数copy()

版本2:

  1. def copy(src_name, dst_name): # 定义函数copy(),实现任意文件的拷贝操作
  2. # 以只读字节的方式打开源文件,赋值给变量fr
  3. # 以写入字节的方式打开源文件,赋值给变量fw
  4. fr = open(src_name, mode='rb')
  5. fw = open(dst_name, mode='wb')
  6. while True:
  7. data = fr.read(4096)
  8. if len(data) == 0:
  9. break
  10. fw.write(data)
  11. fr.close()
  12. fw.close()
  13. copy(源文件路径, 目标文件路径)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/514590
推荐阅读
相关标签
  

闽ICP备14008679号