python语言第11天笔记

文件操作(IO技术)

1 为什么要使用IO技术

前面写的程序数据都没有进行实际的存储,因此 python 解释器执行完数据就消失了。实际开发中,我们经常需要从外部存储介质(硬盘、光盘、U 盘等)读取数据,或者将程序产生的数据存储到文件中,实现“持久化”保存。

2 文本文件和二进制文件

按文件中数据组织形式,我们把文件分为文本文件和二进制文件两大类。

(1)文本文件

文本文件存储的是普通“字符”文本,python 默认为 unicode 字符集(两个字节表示一个字符,最多可以表示:65536 个),可以使用记事本程序打开。但是,像 word 软件编辑的文档不是文本文件。

(2)二进制文件

二进制文件把数据内容用“字节”进行存储,无法用记事本打开。必须使用专用的软件解码。常见的有:MP4 视频文件、MP3 音频文件、JPG 图片、doc 文档等等。
可以这么记,能用记事本打开的就是文本文件,其他都是二进制文件。

3 创建文件对象

python中万物皆对象,因此文件也可以看成是对象,在读写文件之前,必须先创建文件对象。
创建文件对象的格式:
open(文件名[,打开方式])
文件名可以录入全路径,比如“D:\a\b.txt”,也可以用相对路径,即“b.txt”,即与源程序同一个文件夹下。如为了减少“\”的输入,可以在路径前面加 r 表示不转义。
如:f = open(r"d:\b.txt",“w”)
打开方式有以下几种:
在这里插入图片描述
如果我们没有增加模式“b”,则默认创建的是文本文件对象,处理的基本单元是“字符”。如果是二进制模式“b”,则创建的是二进制文件对象,处理的基本单元是“字节”。

4 文本文件的写入

文本文件的写入一般就是三个步骤:创建文件对象、写入数据、关闭文件。
这里写一个简单的测试程序:

f = open(r"a.txt","a")		# 创建文件对象
f.write("itbaizhan\nsxt\n")	# 写入数据
f.close()					# 关闭文件

5 常用编码与中文乱码问题

(1)常用编码

在这里插入图片描述
最初的编码系统是ASCII,这是单字节编码系统,最高位都是0,不同字节只有后面 7 位不一样,也就是说,这套编码系统实际只使用了7位,只能表示 128 个字符。
由于ASCII只能表示英文,而且最高位没有利用,所以后面诞生了一个新的编码系统,即ISO-8859-1,是一个 8 位单字节字符集,它把 ASCII 的最高位也利用起来,它可以表示西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号,并兼容了 ASCII,但它并没有完全用完。
GB2312,GBK,GB18030是由中国大陆开发的字符编码系统,它们都兼容ISO-8859-1,它使用一个字符表示英文,两个字符表示中文。
由于ASCII和ISO-8859-1未能包含所有国家的文字,各国都推出了支持本国文字的字符编码系统,但编码系统不统一,给不同国家之间的信息交换造成不变,因此诞生了统一的文字编码系统,即Unicode。Unicode设计成了固定两个字节,所有的字符都用 16 位。
Unicode由于英文字符也占8位,造成了空间的浪费,并且Unicode 完全重新设计,不兼容 iso8859-1,也不兼容任何其他编码,影响了该编码系统的顺利推广。
由于unicode 不便于传输和存储,因此而产生了 UTF 编码,UTF-8 全称是(8-bit Unicode Transformation Format)。UTF 编码兼容 iso8859-1 编码,同时也可以用来表示所有语言的字符,不过,UTF 编码是不定长编码,每一个字符的长度从 1-4 个字节不等。其中,英文字母都是用一个字节表示,而汉字使用三个字节。

(2)中文乱码问题

windows 操作系统默认的编码是 GBK(Linux 操作系统默认的编码是 UTF-8),当我们用 open()时,是调用操作系统打开文件,因此默认是用 GBK对文件进行读写,而如果使用UTF-8打开,这样就会出现乱码问题,归根结底,就是编码和解码使用的字符集不一样。(python解释器执行程序时,虽然用的是Unicode编码,但在Windows系统中存储和传输时再重新编码成GBK)
比如,在调用open的时候,我设定字符集为utf-8,那么就是按照utf-8读写字符集。

f = open(r"b.txt","w",encoding="utf-8")
f.write("尚学堂\n百战程序员\n")
f.close()

在该项目下出现了一个新的文件,即b.txt,使用终端命令读取文件,就会产生乱码,因为Windows默认使用的是GBK字符集,即用utf-8编码,用GBK解码(使用终端命令读取文件就是“解码”的过程)。
在这里插入图片描述
如果在调用调用open的时候不设置,那么将默认使用GBK进行读写,即编码和解码使用的是同一套字符集。

f = open(r"b.txt","w")
f.write("尚学堂\n百战程序员\n") # 默认使用gbk打开文件
f.close()

再次使用终端命令读取文件
在这里插入图片描述
英文没有乱码问题,因为无论是utf-8(linux系统),还是gbk(Windows系统),都是兼容ASCII字符集的。

(3)write()/writelines()写入数据

write(a):把字符串 a 写入到文件中
writelines(b):把字符串列表写入文件中,自动添加换行符

try:
    f = open(r"c.txt","w")
    strs = ["aa\n","bb\n","cc\n"]   # 如果不添加换行符,那么这几个字符创将挤在同一行
    f.writelines(strs)
except BaseException as e:
    print(e)
finally:
    f.close()

结果
在这里插入图片描述

6 close()关闭文件流

由于文件底层是由操作系统控制,所以我们打开的文件对象必须显式调用 close()方法关闭文件对象。当调用 close()方法时,首先会把缓冲区数据写入文件(也可以直接调用 flush()方法),再关闭文件,释放文件对象。
python程序打开一个文件,此文件在硬盘上,python程序需要调用外部操作系统,由操作系统对硬盘进行读写,程序运行结束,操作系统在读写文件时打开的资源必须全部关闭,因此必须调用close()方法。
在这里插入图片描述
为了确保打开的文件对象正常关闭,一般结合异常机制的 finally 或者 with 关键字实现无论何种情况都能关闭打开的文件对象。
如使用异常机制的话,把close()方法写到 finally 中去,如果用的是 with 上下文管理,那么无需显示调用close()方法。
使用try—finally结构

try:
    f = open(r"c.txt","w")
    strs = ["aa\n","bb\n","cc\n"]   
    f.writelines(strs)
except BaseException as e:
    print(e)
finally:
    f.close()

使用with上下文管理

with open(r"d.txt","a") as f:
    f.write("gaoqi,i love u!")

with 关键字(上下文管理器)可以自动管理上下文资源,不论什么原因跳出 with 块,都能确保文件正确的关闭,并且可以在代码块执行完毕后自动还原进入该代码块时的现场(这里的还原,就相当于关闭所有在 with 块中打开的资源)。

7 文本文件的读取

文件的读取一般使用如下三个方法:

(1)read([size])

这里[size]不是列表,而是表示size可以省略。
从文件中读取 size 个字符,并作为结果返回。如果没有size 参数,则读取整个文件,读取到文件末尾时,会返回空字符串。

with open(r"e.txt","r",encoding="utf-8") as f:
    str = f.read(3)     # 表示读取三个字符
    print(str)

输出

我lo

(2)readline()

读取一行内容作为结果返回。读取到文件末尾,会返回空字符串。

with open(r"a.txt","r") as f:
    while True:
        fragment = f.readline()		# 一行一行地读
        if not fragment:
            break					# 读到最后 fragment 为空,跳出循环
        else:
            print(fragment,end="")

输出

itbaizhan
sxt
itbaizhan
sxt

(3)readlines()

文本文件中,每一行作为一个字符串存入列表中,返回该列表

with open("e.txt","r",encoding="utf-8") as f:
    lines = f.readlines()
    print(lines)

输出

['我love u! #1\n', '尚学堂 #2\n', '百战程序员 #3\n']

(4)把文件当成迭代器进行遍历

with open("e.txt","r",encoding="utf-8") as f:
    for a in f:         # 遍历文件
        print(a,end="")

输出

我love u! #1
尚学堂 #2
百战程序员 #3

8 enumerate()

enumerate方法生成的是枚举对象,当要同时遍历一个可迭代序列的索引和元组的时候,使用enumerate是很方便的。
执行下列程序,体会enumerate的用法

str = 'abcd'
for index, char in enumerate(str):  # 同时遍历索引和元素
    print(index, char)

for tu in enumerate(str):       # 循环没执行一次,enumerate方法就生成一个元组
    print(tu)

输出

0 a
1 b
2 c
3 d
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')

练习,为文本文件 e.txt 的每一行添加行号,比如第一行就在末尾添加“# 1”,e.txt 的初试状态如下:
在这里插入图片描述

with open("e.txt","r",encoding="utf-8") as f:
    lines = f.readlines()
    lines = [ line.rstrip()+" #"+str(index+1)+"\n" for index,line in enumerate(lines)]  # 推导式生成列表

with open("e.txt","w",encoding="utf-8") as f:
    f.writelines(lines)

结果
在这里插入图片描述

rstrip是去掉字符串末尾的指定字符,默认是空格,执行下面的程序,体会它的用法

str = "     this is string example....wow!!!     "
print("原来长度", len(str))
str = str.rstrip()          # 未指定删除什么,那就删除空格
print(str)
print("现在长度", len(str))
print("+"*50)
str = "88888888this is string example....wow!!!8888888"
print("原来长度", len(str))
str = str.rstrip('8')
print(str)
print("现在长度", len(str))

输出

原来长度 42
     this is string example....wow!!!
现在长度 37
++++++++++++++++++++++++++++++++++++++++++++++++++
原来长度 47
88888888this is string example....wow!!!
现在长度 40

9 二进制文件的读写

二进制文件的处理流程和文本文件流程一致。首先还是要创建文件对象,不过,我们需要指定二进制模式(也就是在w、r、a的后头加 b),从而创建出二进制文件对象。
如,把 aa.gif 拷贝到 aa_copy.gif 中

with open("aa.gif","rb") as f:
    with open("aa_copy.gif","wb") as w:
        for line in f.readlines():      # 每次读一行
            w.write(line)

print("图片拷贝完成.........")

10 序列化与反序列化

Python 中,一切皆对象,对象本质上就是一个“存储数据的内存块”。有时候,我们需要将“内存块的数据”保存到硬盘上,或者通过网络传输到其他的计算机上。这时候,就需要“对象的序列化和反序列化”。
序列化指的是:将对象转化成“串行化”数据形式,相当于给数据编号,存储到硬盘或通过网络传输到其他地方。
反序列化是指相反的过程,将读取到的“串行化数据”转化成对象。
序列化和反序列化需要导入pickle模块,序列化用 pickle.dump(obj, file),obj 就是要被序列化的对象,file 指的是存储的文件;反序列化用 pickle.load(file) 从 file 读取数据,反序列化成对象

import pickle

a1 = "高淇"
a2 = 234
a3 = [10,20,30,40]

with open("data.dat","wb") as f:
    pickle.dump(a1,f)
    pickle.dump(a2,f)
    pickle.dump(a3,f)

with open("data.dat","rb") as f:
    b1 = pickle.load(f);
    b2 = pickle.load(f);
    b3 = pickle.load(f)
    print(b1);print(b2);print(b3)   # 一行写多条语句,要用分号隔开

    print(id(a1));print(id(b1))     
    # 看一下反序列化后的对象与原对象的地址是否相同

输出

高淇
234
[10, 20, 30, 40]
39643728
40175728

11 csv文件的操作

csv(Comma Separated Values)是逗号分隔符文本格式,常用于数据交换、Excel文件和数据库数据的导入和导出。
与 Excel 文件不同,CSV 文件中:
(1)值没有类型,所有值都是字符串;
(2)不能指定字体颜色等样式;
(3)不能指定单元格的宽高,不能合并单元格;
(4)没有多个工作表;
(5)不能嵌入图像图表
Python 标准库的模块 csv 提供了读取和写入 csv 格式文件的对象。
我们在 excel 中建立一个简单的表格:
在这里插入图片描述
然后另存为"csv(逗号分隔)",我们打开查看这个 csv 文件内容:
在这里插入图片描述
分别使用 csv.reader 和 csv.writer 方法读取和写入
也可以使用

import csv

with open("dd.csv","r") as f:
    a_csv = csv.reader(f)	
    # 创建 csv.reader 对象,它是一个包含所有数据的列表,每一行为一个元素
    for row in a_csv:	# 循环打印各行内容
        print(row)	
    # 和zip对象类似,csv.reader对象也是只能用一次,遍历完之后,就无效了
    
with open("ee.csv","w") as f:
    b_csv = csv.writer(f)		# 创建 csv.writer 对象
    b_csv.writerow(["ID","姓名","年龄"])	# 调用 writerow 函数将列表中的元素写入 csv 文件,每次写一行
    b_csv.writerow(["1001","高淇","18"])	

    c = [["1002","希希","3"],["1003","东东","4"]]
    b_csv.writerows(c)		# 每个子列表分别作为一行,一次性写入多行

输出

['ID', '姓名', '年龄', '薪资']
['1001', '高淇', '18', '50000']
['1002', '高八', '19', '30000']
['1003', '高九', '20', '20000']

ee.csv 中的内容为
在这里插入图片描述

11 os模块

os 模块可以帮助我们直接对操作系统进行操作。我们可以直接调用操作系统的可执行文件、命令,直接操作文件、目录等等。是系统运维的核心基础。

(1)os 模块-调用操作系统命令

·os.system 可以帮助我们直接调用系统的命令
os.system(“notepad.exe”) 引号内输入命令和在下面截图的方框输入命令的效果是一致的。
在这里插入图片描述

(2)os.startfile:直接调用可执行文件

os.startfile(“D:\Program Files (x86)\Tencent\WeChat\WeChat.exe”),可以打开微信。

(3)文件和目录操作

执行下面程序,了解文件和目录的相关操作,了解即可,以后用到了再具体学

#coding=utf-8
#测试os模块中,关于文件和目录的操作
import os

#############获取文件和文件夹相关的信息################
# print(os.name)              # 返回操作系统的名字,windows->nt    linux和unix->posix
# print(os.sep)               # 返回分隔符,windows->\     linux和unix->/
# print(repr(os.linesep))     # 返回换行符 windows->\r\n   linux-->\n\
# repr函数用来取得对象的规范字符串表示,返回一个字符串,与str()类似
# repr() 与 str() 的区别是什么,这个暂时先不管,以后需要区分的时候再去搞明白

# print(os.stat("my02.py"))   # 获得文件的信息

##############关于工作目录的操作###############
# print(os.getcwd())
# os.chdir("d:")      # 改变当前的工作目录为:d:盘根目录
# os.mkdir("书籍")    # 创建目录,这里用的是相对路径,
# 这条语句执行之后,将在D盘下新建“书籍”,因为前面已经修改了工作空间

################创建目录、创建多级目录、删除#############
# os.mkdir("书籍")    # 在当前工作空间中创建一个文件夹
# os.rmdir("书籍")   # 删除目录,相对路径都是相对于当前的工作目录

# os.makedirs("电影/港台/周星驰")     # 创建多级目录
# os.removedirs("电影/港台/周星驰")   # 删除工作目录,只能删除空目录

# os.makedirs("../音乐/香港/刘德华")    # 在上一级目录中创建多级目录,../指的是上一级目录

# os.rename("电影","movie")            # 修改文件或文件夹的名字

dirs = os.listdir("movie")              # 以列表的形式返回一级子目录和子文件
print(dirs)
#############################

遇到一个新的模块的时候,不是把模块中的方法都过一遍,而是把暂时用得着的先学会,其他的部分将来用的时候再学,以建立只是体现为先。

(4)os.path 模块

os.path 模块提供了目录相关(路径判断、路径切分、路径连接、文件夹遍历)的操作
执行下面程序,了解 os.path 简单的使用,了解即可,以后用到了再具体学

# coding=utf-8
# 测试os.path中关于目录、路径的操作

import os
import os.path      #from os import path

############判断:绝对路径、是否目录、是否文件、文件是否存在#############
# print(os.path.isabs("d:/a.txt"))    # 判断是否为绝对路径
# print(os.path.isdir("d:/a.txt"))    # 判断是否为目录(False)
# print(os.path.isfile("d:/a.txt"))   # 判断是否为文件(True)
# print(os.path.exists("d:/a.txt"))   # 判断文件或文件夹是否存在

##############获得文件基本信息################
# print(os.path.getsize("b.txt"))     # 返回文件的大小
# print(os.path.abspath("b.txt"))     # 返回绝对路径
# print(os.path.dirname("d:/a.txt"))  # 返回目录的路径

# print(os.path.getctime("b.txt"))    # 返回文件的最后访问时间
# print(os.path.getatime("b.txt"))    # 返回文件的最后修改时间
# print(os.path.getmtime("b.txt"))    #

##############对路径的操作#####################
path = os.path.abspath("b.txt")
print(os.path.split(path))              # 对文件进行分割,以列表形式返回
print(os.path.splitext(path))           # 从路径中分割文件的扩展名

print(os.path.join("aa","bb","cc"))     # 将几个字符串用路径分隔符链接起来

输出

('F:\\拜师培训\\3350_Python编程-pycharm版\\第十节文件处理课程源码和资料\\mypro_io(本章源代码)\\test_os', 'b.txt')
('F:\\拜师培训\\3350_Python编程-pycharm版\\第十节文件处理课程源码和资料\\mypro_io(本章源代码)\\test_os\\b', '.txt')
aa\bb\cc

练习,列出指定目录下所有的.py 文件,并输出文件名

#coding=utf-8
# 列出工作目录下所有的.py文件,并输出文件名

import os

path = os.getcwd()

file_list = os.listdir(path)  #列出子目录、子文件
for filename in file_list:
    if filename.endswith("py"):     # endswith("py") 以 py 结尾的字符串则返回True
        print(filename,end="\t")

print("###############")
# 使用列表推导式
file_list2 = [filename for filename in os.listdir(path) if filename.endswith("py") ]
for f in file_list2:
    print(f,end="\t")

输出

my01.py	my02.py	my03.py	my04.py	my05.py	###############
my01.py	my02.py	my03.py	my04.py	my05.py

(5)os.walk()递归遍历所有文件和目录

os.walk()方法:返回一个生成器对象,用for遍历该生成器对象,每次返回 3 个元素的元组,(dirpath, dirnames, filenames),
dirpath:要列出指定目录的路径;
dirnames:目录下的所有文件夹;
filenames:目录下的所有文件
执行下面的程序,观察os.walk()方法的使用。

#coding=utf-8
#测试os.walk()递归遍历所有的子目录和子文件

import os

all_files = []
path = os.getcwd()
list_files = os.walk(path)
print(type(list_files))     # list_files 是一个生成器对象


for dirpath, dirnames, filenames in list_files:
    for dir in dirnames:
        all_files.append(os.path.join(dirpath,dir))     # 将工作空间和子目录进行拼接
    for file in filenames:
        all_files.append(os.path.join(dirpath,file))    # 将工作空间和子文件进行拼接

# 打印所有的子目录和子文件
for file in all_files:
    print(file)

12.拷贝和压缩

(1)拷贝

shutil 模块是 python 标准库中提供的,主要用来做文件和文件夹的拷贝、移动、删除等;还可以做文件和文件夹的压缩、解压缩操作。
os 模块提供了对目录或文件的一般操作。shutil 模块作为补充,提供了移动、复制、压缩、解压等操作,这些 os 模块都没有提供。

(2)压缩

有两种压缩方式,一种是使用shutil模块,另一种是是使用 zipfile 模块

#coding=utf-8
#测试shutil模块的用法:拷贝、压缩

import shutil
import zipfile

shutil.copyfile("1.txt","1_copy.txt")   # 拷贝文件,如果1_copy.txt已经存在,那就覆盖
# shutil.copytree("movie/港台","电影")   # 拷贝目录,"电影"目录不存在时才能正常拷贝
# shutil.copytree("movie/港台","电影",ignore=shutil.ignore_patterns("*.txt","*.html"))
# ignore表示要忽略的文件,这里 * 表示通配符,即拷贝的时候,不拷贝txt和html后缀的文件

# 压缩、解压缩
# shutil.make_archive("电影/gg","zip","movie/港台")
# 把"movie/港台"压缩到"电影/gg"中,压缩文件的后缀名为".zip"
# 最后生成了一个名为 “gg.zip” 的压缩文件

z1 = zipfile.ZipFile("d:/a.zip","w")  # 使用 zipfile 模块,先建立一个压缩对象,然后再写入,类似于文件操作
z1.write("1.txt")
z1.write("1_copy.txt")
z1.close()        # 关闭压缩对象

z2 = zipfile.ZipFile("d:/a.zip","r")  # 建立一个解压缩对象
z2.extractall("电影")   # 把压缩包解压到电影目录中
z2.close()        # 关闭压缩对象

练习:递归算法打印目录树

# coding=utf-8
# 递归打印所有的目录和文件

import os

allfiles = []
def getAllFiles(path,level):
    childFiles = os.listdir(path)   # 以列表的形式返回一级子目录和文件
    for file in childFiles:         # 遍历列表
        filepath = os.path.join(path,file)  # 将文件/文件夹名(file)与路径名(path)连接
        if os.path.isdir(filepath):         # 如果是文件夹,则调用本方法
            getAllFiles(filepath,level+1)
        allfiles.append("\t"*level+filepath)    # 不管是文件还是文件夹,都追加到列表中


getAllFiles("test_os",0)

for f in allfiles:
    print(f)

输出

test_os\b.txt
	test_os\movie\大陆
	test_os\movie\尚学堂.mp4
	test_os\movie\日本
			test_os\movie\港台\周星驰\功夫.mp4
		test_os\movie\港台\周星驰
	test_os\movie\港台
test_os\movie
test_os\my01.py
test_os\my02.py
test_os\my03.py
test_os\my04.py
test_os\my05.py

os.walk()方法的底层,其实也是调用了递归方法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值