Python基础学习Day10

Day 10

第八章 文件操作(IO技术)

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

很多软件系统是将数据存储在数据库中;数据库实际也是基于文件形式存储的,本章我们就学习文件的相关操作。

文本文件和二进制文件

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

1.文本文件

   文本文件存储的是普通“字符”文本,默认为unicode字符集(两个字节表示一个符号,最多可以表示:65536(2的16次方)个,足够表示所有的语言),可以使用记事本程序打开,但是,像word软件编辑的文档不是文本文件。(以字符为单位)

2.二进制文件

   二进制文件把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件解码,常见的有:MP4音频文件、MP3音频文件、JPG图片、doc文档等等。(以字节为单位)


文件操作相关模块概述

Python标准库中,如下文件操作相关的模块,我们会陆续介绍学习。

名称

说明

io模块

文件流的输入和输出操作

(input output)

os模块

基本操作系统功能,包括文件操作

glob模块

查找符合特定规则的文件路径名

fnmatch模块

使用模式来匹配文件路径名

fileinput模块

处理多个输入文件

filecmp模块

用于文件的比较

cvs模块

用于cvs文件处理

pickle和cPickle

用于序列化和反序列化

xml包

用于xml数据处理

bz2、gzip、zipfile、zlib、trafile

用于处理压缩和解压缩文件(分别对应不同算法)

创建文件对象open()

open()函数用于创建文件对象(python中一切皆对象),基本语法格式如下:
open[文件名[,打开方式]]

如果只是文件名,代表在当前目录下的文件。文件名可以录入全路径,比如

D:\a\b.txt。为了减少“\”的输入,可以使用原始字符串:r“d:\b.txt”。

示例如下:

                    f = open(r”d:\b.txt”,”a”)

打开方式有如下几种:

模式

描述

r

读read模式(把文件内容读入)

w

写write模式,如果文件不存在则创建;如果文件存在,则重新写内容

a

追加模式,如果文件不存在则创建,如果文件存在,则在文件末尾追加内容

b

二进制模式(可与其他模式组合使用)

+

读、写模式(可与其他模式组合使用)

文本文件对象和二进制对象的创建:

    如果我们没有增加模式“b”,则默认创建的是文本文件对象,处理的基本

单元是“字符”。如果是二进制模式“b”,则创建的是二进制文件对象,处理

的基本单元是“字节”

例:f = open(rd\b.jpg,bw) 处理的是二进制文件

文本文件的写入

基本的文件写入操作

文本文件的写入一般就是三个步骤:

1.创建文件对象

2.写入数据

3.关闭文件对象

Python文件要把数据写入硬盘中,python文件由解释器执行,解释器运行于操

作系统os(中),操作系统直接操作硬盘。python文件把数据给解释器,解释

器给操作系统,操作系统给硬盘。因为过程中也调用了操作系统的资源,所以数

据处理完后要关闭解释器和操作系统打开的文件资源

我们首先创建一个小程序,体验一下文本文件的写入操作。

【操作】文本写入操作简单测试

f= open(r"d:\a.txt","a")
s = '尚学堂\n百战程序员\n'
f.write(s)
f.close()

结果:

常用编码介绍

在操作文本文件时,经常会操作中文,这时候就经常会碰到乱码问题。为了让大

家有能力解决中文乱码问题,这里简单介绍一下各种编码问题。

常用编码之间关系如下

一个字节8位,可以表示2^8 = 256个字符

ASCII

0-31表示控制字符如回车、退格、删除等;32-126表示打印字符既可以通过键盘输入并且能显示出来的字符;其中48-57位0到9十个阿拉伯数字,65-90位26个大写英文字母,97-122号为26个小写英文字母,其余为一些标点符号、运算符号,具体可以参考ASCII标准表。

 ISO8859-1

UTF-8

中文乱码问题

   

 windows操作系统默认的编码是GBK,Linux操作系统默认的编码是UTF-8。当我们用open()时,调用的是操作系统打开的文件,默认的编码是GBK。

【示例】中文字符文件,乱码出现测试

#测试写入中文
f = open(r"b.txt","w")
f.write("尚学堂\n百战程序\n")
f.close()

结果:

 【示例】可以直接用编码

#测试写入中文
f = open(r"b.txt","w",encoding='utf-8')
f.write("尚学堂\n百战程序\n")
f.close()

write()/writelines()写入数据

write(a):把字符串a写入到文件中

writelines(b):把字符串列表写入文件中,不添加换行符

【操作】添加字符串列表数据到文件中

#测试写入中文
f = open(r"d:\a.txt","w",encoding='utf-8')
s = {'高崎\n','高老三\n','高老四\n'}
f.writelines(s)
f.close()

结果:

 close()关闭文件流

由于文件底层是由操作系统控制,所以我们打开的文件对象必须显示调用close()方法关闭文件对象,当调用close()方法时,首先会把缓冲区数据写入文件(也可以直接调用flush()方法),再关闭文件,释放文件对象

     

为了确保打开的文件对象正常关闭,一般结合异常机制的finally或者with关键字实现无论何种情况都能关闭打开的文件对象

【操作】结合异常机制finally确保关闭文件对象

try:
    f = open(r"my01.txt","a")
    str = "gaoqi"
    f.write(str)
except BaseException as e:
    print(e)
finally:
    f.close()

with语句(上下文管理器)

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

【示例】使用with管理文件写入操作

s = {'高崎\n','高老二\n','高老四\n'}
with open(r"d.txt","w") as f:
    f.write('gaoqi,i love u')

结果:

文本文件的读取

文件的读取一般使用如下三个方法:(python中文本文件以字符为单位来处理,英文算一个字符,中文也算一个字符)

1.read([size])

从文件中读取size个字符,并作为结果返回。如果没有size参数,则读取整个文件。读取到文件末尾,会返回空字符串

2.readline()

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

3.readlines()

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

【测试】文件较小,一次将文件内容读入到程序中和读取一个文件前3个字符

#测试文件读取
with open(r"e.txt",'r',encoding='utf-8') as f: # 'r'表示读
print(f.read())
print(f.read(3))

结果:

我love u!

百战程序员

上学堂

我lo

【操作】按行读取一个文件

#按行读取一个文件
with open(r"e.txt",'r') as f:
    while True:
        fragment = f.readline()   #读一行
        if not fragment:  #如果到了末尾
            break
        else:
            print(fragment,end='')

结果:

我love u!

百战程序员

上学堂

【操作】使用迭代器(每次返回一行)读取文本文件

with open(r"e.txt",'r',encoding='utf-8') as f:
    for a in f:
        print(a,end='')

结果:

我love u!

百战程序员

上学堂

【操作】给每一行加行号

a = ['我love u!\n','尚学堂\n','百战程序员\n']
b = enumerate(a)  #把序列传进来,把每一个元素用元组排序
print(a)
print(list(b))
c = [ temp.rstrip()+" #" +str(index) for index,temp in enumerate(a)]
print(c)

结果:

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

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

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

【操作】写入文件

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

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

结果:

---->

['我#0l#1o#2v#3e#4#5u#6!#7##80#9百#10战#11程#12序#13员#14##151#16上#17学#18堂#19##202#21']

二进制文件的读取和写入

二进制文件的处理流程和文本文件流程一致。首先还是要创建文件对象,不过,我们需要指定二进制模式,从而创建出二进制文件对象。例如:

  f=open(r”d:\a.txt”,’wb’)  #可写的、重写模式的二进制文件对象

  f=open(r”d:\a.txt”,’ab’)  #可写的、追加模式的二进制文件对象

  f=open(r”d:\a.txt”,’rb’)  #可读的二进制文件对象

创建好二进制文件对象后,仍然可以使用write()、read()实现文件的读写操作

【操作】 读取图片文件,实现文件的拷贝

with open('img.png','rb') as f:
    with open('img_copy.png','wb') as w:
        for line in f.readlines():
            w.write(line)
print('图片拷贝完成')

 结果:

文件对象的常用属性和方法

文件对象封装了文件相关的操作。在前面我们学习了通过文件对象对文件进行读写操作。本节我们详细列出文件对象的常用属性和方法,并进行说明

文件对象的属性

属性

说明

name

返回文件的名字

mode

返回文件的打开模式(r,a,w)

closed

若文件关闭则返回True

文件对象的打开模式

模式

说明

r

读模式

w

写模式

a

追加模式

b

二进制模式(可与其他模式组合)

+

读写模式(可以其他模式组合)

文件对象的常用方法

方法名

说明

read([size])

从文件中读取size个字节或字符的内容返回。若省略[size],则读取到文件末尾,即一次读取文件所有内容

readline()

把文本文件中读取一行内容

readlines()

把文本文件中每一行都作为独立的字符串对象,并将这些对象放入列表返回

write(str)

将字符串str内容写入文件

writelines(s)

将字符串列表s写入文件,不添加换行符

seek(offset [,whence])

文件指针移动到新的位置,offset表示相对于whence的多少个字节的偏移量;

offset:

off为正往结束方向移动,为负往开始方向移动

whence不同的值代表不同含义:

0:从文件头开始计算(默认值)

1:从当前位置开始计算

2:从文件尾开始计算

tell()

返回文件指针的当前位置

truncate([size])

不论指针在什么位置,只留下指针前size个字节的内容,其余全部删除;

如果没有传入size,则当指针当前位置到文件末尾内容全部删除

flush()

把缓冲区的内容写入文件,但不关闭文件

close()

把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源

【测试】

with open('ee.txt','r',encoding='utf-8') as f:
    print('文件名是:{0}'.format(f.name))
    print(f.tell()) #指针的位置
    print('读取的内容:{0}'.format(f.readline()))
    print(f.tell())
    f.seek(3)
    print('读取的内容:{0}'.format((f.readline())))

(读取了第一行我’love u! #1’,文件开头是0,‘我’占3个字节,‘love’占4个字节,‘ ’空格占一个字节,‘u’占一个字节,‘!’占一个字节,‘ ’空格占一个字节,‘#1’占两个字节,换行符占一个字节,因此读完第一行后,指针位置在15,即‘尚’前面)(f.seek(3)即把指针移动到偏移量3,然后从头开始读,因此没有读取出‘我’)

结果:

文件名是:ee.txt

0

读取的内容:我love u !  #1

15

读取的内容:love u! #1

使用pickle序列化

python中,一切皆对象,对象本质上就是一个“存储数据的内存块”。有时候,我们需要将“内存块的数据”保存到硬盘上,或者通过网络传输到其他的计算机上。这时候,就需要“对象的序列化和反序列化”。对象的序列化机制广泛的应用在分布式、并行系统上

序列化指的是:将对象转化成“串行化”数据形式,存储到硬盘或通过网络传输到其他地方。反序列化是指相反的过程,将读取到的“串行化数据”转化成对象

我们可以使用pickle模块中的函数,实现序列化和反序列化

序列化我们使用:

   pickle.dump(obj, file)     obj就是要被序列化的对象,file指的是存储的文件

   pickle.load(file)          从file读取数据,反序列化成对象

【操作】将对象序列化到文件中

import pickle
with open(r'd:\a.dat','wb') as f: #dat是二进制文件
    a1 = '高崎'
    a2 = 234
    a3 = [20,30,40]

    pickle.dump(a1,f)      #把a1对象存到f文件
    pickle.dump(a2,f)
    pickle.dump(a3,f)

【操作】将获得的数据反序列化成对象

import pickle
with open(r'd:\a.dat','rb') as f:
    a1 = pickle.load(f)
    a2 = pickle.load(f)
    a3 = pickle.load(f)
    print(a1)
    print(a2)
    print(a3)
print(id(a1));print(id(a2))

执行结果:

高崎

234

[20, 30, 40]

2523987522256

140714953588400

CSV文件的操作

csv(Comma Separated Values)是逗号分隔符文本格式,常用于数据交换、Excel文件和数据库数据的导入和导出。与Excel文件不同,CSV文件中

      

·值没有类型,所有值都是字符串(只能处理简单的字符串)

·不能指定字体颜色等样式

·不能指定单元格的宽高,不能合并单元格

·没有多个工作表

·不能嵌入图像图表

python标准库的模块csv提供了读取和写入csv格式文件的对象。

我们在excel中建立一个简单的表格:

 另存为“csv(逗号分割)”,我们打开查看这个csv文件的内容:

csv.reader对象和csv文件读取

【操作】csv文件的读取和导入

#测试csv文件的读取和导入
import csv

with open("a.csv",'r') as f:
    a_csv = csv.reader(f)
   #print(list(a_csv))
    for row in a_csv:
        print(row)

with open('ee.csv','w') as f:
    b_csv = csv.writer(f)
    b_csv.writerow(['ID','姓名','年龄'])
    b_csv.writerow(['100','张三疯','50'])
    c=[['101','李四','30'],['102','王五','22']]
    b_csv.writerows(c)

结果:
['ID', '姓名', '年龄', '薪资']

['1001', '高崎', '18', '50000']

['1002', '高八', '19', '30000']

['1003', '高九', '20', '20000']

os(operating system)和os.path模块

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

os调用操作系统文件和命令

·os.system可以帮助我们直接调用系统的命令

【示例】os.system调用windows系统的记事本程序,cmd

import os
os.system('notepad.exe')
os.system('cmd')

结果:

 【示例】ping www.baidu.com

import os

os.system('ping www.baidu.com')

 结果:

 【示例】直接调用可执行文件(微信)

import os
os.startfile(r"D:\Program Files (x86)\Tencent\WeChat\WeChat.exe")

os模块和目录操作

   我们可以通过前面讲的文件对象实现对于文件内容的读写操作。如果,还需要对文件和目录做其他操作,可以使用os和os.path模块

os模块下常用操作文件的方法

方法名

描述

remove(path)

删除指定的文件

rename(src,dest)

重命名文件或目录

stat(path)

返回文件的所有属性

listdir(path)

返回path目录下的文件和目录列表

os模块下关于目录操作的相关方法,汇总如下:

方法名

描述

mkdir(path)    #makedir

创建目录

makedirs(path1/path2/path3/...)

创建多级目录

rmdir(path)  #removedir

删除目录

removedirs(path1/path2..)

删除多级目录(只能删除空的目录)

getcwd()

返回当前工作目录:current work dir

chdir(path)    #changedir

把path设为当前工作目录

walk()

遍历目录树

sep

当前操作系统所使用的路径分隔符

【示例】os模块:创建、删除目录、获取文件信息等

【文件和文件夹相关的信息】

#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() 函数将对象转化为供解释器读取的形式。返回一个对象的 string 格式。
print(os.stat('02.py'))

结果:

nt

\

'\r\n'

os.stat_result(st_mode=33206, st_ino=5348024557647051, st_dev=2620880335, st_nlink=1, st_uid=0, st_gid=0, st_size=1161, st_atime=1641783240, st_mtime=1641783240, st_ctime=1641781008)

【关于工作目录的操作】

print(os.getcwd())  #当前的工作空间
#os.chdir('d:')    #改变d盘设为工作目录
#os.mkdir('书籍')   #创建子目录,书籍建在d盘

结果:

C:\Users\Administrator\PycharmProjects\MyDemo\test_os

【创建目录、创建多级目录、删除】

#os.mkdir('书籍')
#os.rmdir('书籍')  #相对路径都是相对于当前的工作目录

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

#os.makedirs('../音乐/香港/刘德华') #../指的是上一级目录

#os.rename('电影','movie')  #把目录名电影改为movie

dirs = os.listdir('movie')  #查看子目录
print(dirs)

结果:

['大陆', '港台']

os.path模块

os.path模块提供了目录相关(路径判断、路径切分、路径连接、文件夹遍历)的操作

方法

描述

isabs(path)

判断path是否绝对路径

isdir(path)

判断path是否为目录

isfile(path)

判断path是否为文件

exists(path)

判断指定路径的文件是否存在

getsize(filename)

返回文件的大小

abspath(path)

返回绝对路径

dirname(p)

返回目录的路径

getatime(filename)

返回文件的最后访问时间

getmtime(filename)

返回文件的最后修改时间

getctime(filename)

返回文件的创建时间

walk(top,func,arg)

递归方式遍历目录

join(path,*paths)

连接多个path

split(path)

对路径进行分割,以列表形式返回

splitext(path)

从路径中分割文件的扩展名

【操作】测试os.path中关于目录、路径的操作

【判断:绝对路径、是否目录、是否文件、文件是否存在】

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

结果:

True

False

True

True

【获得文件基本信息】

print(os.path.getsize('b.txt'))
print(os.path.abspath('b.txt'))
print(os.path.dirname('b,txt'))

print(os.path.getctime('b.txt')) #创建时间
print(os.path.getatime('b.txt'))
print(os.path.getmtime('b.txt'))

结果:
16

C:\Users\Administrator\PycharmProjects\MyDemo\test_os\b.txt

1641786490.3599086

1641786541.197391

1641786541.197391

【对路径的操作】

path = os.path.abspath('b.txt')
print(os.path.split(path))
print(os.path.splitext(path))

print(os.path.join('aa','bb','cc'))

结果:

('C:\\Users\\Administrator\\PycharmProjects\\MyDemo\\test_os', 'b.txt')

('C:\\Users\\Administrator\\PycharmProjects\\MyDemo\\test_os\\b', '.txt')

aa\bb\cc

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

import os

path = os.getcwd()

file_list = os.listdir(path)  #列出子目录、子文件
for filename in file_list:
    if filename.endswith('py'):
        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')

结果:

01.py 02.py 03.py 04.py ####列表推导式####

01.py 02.py 03.py 04.py

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

os.walk()方法:

返回一个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)

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)

结果:

 

shutil模块(拷贝和压缩)

     shutil模块是python标准库中提供的,主要用来做文件和文件夹的拷贝、移动、删除等;还可以做文件和文件夹的压缩、解压缩操作。

     os模块提供了对目录或文件的一般操作。shutil模块作为补充,提供了移动、复制、压缩、解压等操作,这些os模块都没有提供

【操作】测试shutil模块的用法,拷贝

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

import shutil

#文件拷贝
#shutil.copyfile('1.txt','1_copy.txt')

#文件夹拷贝(’电影‘目录不存在时才能正常拷贝)
#ignore指不拷贝的内容(此处不拷贝.txt和.html)
shutil.copytree('movie/港台','电影',ignore=shutil.ignore_patterns('*.txt','*.html'))

结果:

【操作】文件压缩 

import shutil

#####压缩、解压缩####
shutil.make_archive('电影/gg','zip','movie/港台')
#(压缩完之后压缩包所在的位置和名字,压缩包的格式,压缩的内容)

 结果:

 

用zipfile压缩

【操作】压缩文件,解压缩

import zipfile
z1 = zipfile.ZipFile('d:/a.zip','w')
z1.write('1.txt')
z1.write('1_copy.txt')
z1.close()

#解压缩
x2 = zipfile.ZipFile('d:/a.zip','r')
x2.extractall('电影')
x2.close()

结果: 

         

 

递归算法

递归是一种常见的解决问题的方法,即把问题逐渐简单化。递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者简介的调用自己。

利用递归可以用简单的程序来解决一些复杂的问。比如:斐波那契数列的计算、汉诺塔、快排等问题

递归结构包括两个部分:

·定义递归头。解答:什么时候不调用自身方法。如果没有头、将陷入死循环,也就是递归的结束条件。

·递归体。解答:什么时候需要调用自身方法。

【操作】测试递归算法

#coding = utf-8
#测试递归算法
num = 1
def a1():
    global num #如果要在函数内部改变全局变量的值,增加global关键字声明一下
    num +=1
    print('a1')
    if num<3:
        a1()

a1()

结果:

a1

a1

【示例】使用递归求n!

#coding = utf-8

#使用递归计算n的阶乘

def factorial(n):
    if n == 1:
        return n
    else:
        return n*factorial(n-1)

print(factorial(5))

结果:120

【操作】递归打印所有的目录和文件

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

import os

allfiles = []
def getAllFiles(path,level):
    childFiles = os.listdir(path)
    for file in childFiles:
        filepath = os.path.join(path,file)
        if os.path.isdir(filepath):
            getAllFiles(filepath,level-1)  #如果是目录的话
        #print('\t'*level+filepath)
        allfiles.append('\t'*level+filepath)

getAllFiles(r"C:\Users\Administrator\PycharmProjects\MyDemo\递归",0)
for f in reversed(allfiles):
    print(f)

结果:

E:\Softwares\Anaconda3\python.exe C:/Users/Administrator/PycharmProjects/MyDemo/递归/递归打印所有目录文件.py

C:\Users\Administrator\PycharmProjects\MyDemo\递归\递归打印所有目录文件.py

C:\Users\Administrator\PycharmProjects\MyDemo\递归\递归.py

C:\Users\Administrator\PycharmProjects\MyDemo\递归\n!.py

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值