Python(6): 文件及IO操作

1 文件

1.1 概述

  • 存储在计算机的存储设备中的一组数据序列就是文件。
  • 不同类型的文件通过后缀名进行区分。
  • 在Python中,文件被分为两类:①文本文件;②二进制文件。

1.2 文件的基本操作

  • 打开/创建文件:name=open(filename,mode,encoding)

    • filename: 文件名
    • mode: 打开模式(详见下表)

      打开模式说明
      r以只读模式打开,文件指针在文件的开头,如果文件不存在,程序抛异常
      rb以只读模式打开二进制文件,如图片文件
      w覆盖写模式,文件不存在创建,文件存在则内容覆盖
      wb覆盖写模式写入二进制数据,文件不存在创建,文件存在则内容覆盖
      a追加写模式,文件不存在创建,文件存在则在文件最后追加内容
      +与w/r/a等一同使用,在原功能基础上增加同时读写功能
    • encoding: 编码模式
    • 若文件名在目录中未创建,则会自动创建一个文件,不会报错。
  • 操作文件:

    • name.read() 只读
    • name.write(s) 覆盖写入

      读写方法说明
      file.read(size)读取指定字节的字符,若无参数则读取全部,结果为字符串类型 括号中为所读取字符数,而非字节大小
      file.readline(size)读取一行数据,若给定参数,则读取改行指定字节的字符,结果为字符串类型
      file.readlines()读取全部内容,结果为列表类型
      file.write(s)字符串s写入文件
      file.writelines(lst)内容全部为字符串的列表lst写入文件
      file.seek(offset)改变文件操作指针的位置 注:指针默认位置为文档首端,括号中为字节大小 (英文=1B,中文GBK编码=2B,UTF-8编码=3B)
  • 关闭文件:name.close()

1.2.1 例11.1:文件的基本读写

def my_write(): # 定义函数
    # (1)(创建)打开文件
    file=open('a.txt','w',encoding='utf-8')
    # (2)操作文件
    file.write('The Great Chinese Dream')
    # (3)关闭文件
    file.close()
    
# 读取
def my_read():
    file=open('a.txt','r',encoding='utf-8')
    s=file.read()
    print(type(s),s)
    file.close()
    
# 主程序运行
if __name__ == '__main__':
    my_write() # 调用函数
    my_read()

1.2.2 例11.2:文件的写入操作

def my_write(s):
    file=open('b.txt','a',encoding='utf-8')
    file.write(s)
    file.write('\n')
    file.close()
def my_write_list(file,lst):
    f=open(file,'a',encoding='utf-8')
    f.writelines(lst)
    f.close

if __name__ == '__main__':
    my_write('伟大的中国梦')
    my_write('北京欢迎您')
    my_write_list('c.txt',['姓名\t','年龄\t','成绩\n','张三\t','30\t','98'])

1.2.3 例11.3:文件的读取操作

1.2.3.1 全部读取(第7行)

def my_read(filename):
    file=open(filename,'w+',encoding='utf-8') 
    # 'w+'兼备写入和读取功能
    file.write('你好啊') # 写入完成,指针在最后
    file.seek(0) # 把指针置于最前端
    # 读取
    s=file.read() # 读取全部
    print(type(s),s)
    file.close()

if __name__ == '__main__':
    my_read('d.txt')

1.2.3.2 读取指定字符数(第7行)

def my_read(filename):
    file=open(filename,'w+',encoding='utf-8') 
    # 'w+'兼备写入和读取功能
    file.write('你好啊') # 写入完成,指针在最后
    file.seek(0) # 把指针置于最前端
    # 读取
    s=file.read(2) # 2指的是两个字符,而非字节
    print(type(s),s)
    file.close()

if __name__ == '__main__':
    my_read('d.txt')

1.2.3.3 读取一行数据(第7行)

def my_read(filename):
    file=open(filename,'w+',encoding='utf-8') 
    # 'w+'兼备写入和读取功能
    file.write('你好啊') # 写入完成,指针在最后
    file.seek(0) # 把指针置于最前端
    # 读取
    s=file.readline() # 读取一行数据
    print(type(s),s)
    file.close()

if __name__ == '__main__':
    my_read('d.txt')

1.2.3.4 读取一行数据的指定个字符(第7行)

def my_read(filename):
    file=open(filename,'w+',encoding='utf-8') 
    # 'w+'兼备写入和读取功能
    file.write('你好啊') # 写入完成,指针在最后
    file.seek(0) # 把指针置于最前端
    # 读取
    s=file.readline(2) # 读取一行数据的两个字符
    print(type(s),s)
    file.close()

if __name__ == '__main__':
    my_read('d.txt')

1.2.3.5 读取所有行(第7行)

注意:与以上不同,readlines() 括号中的数字表示行数,输出为列表类型。

def my_read(filename):
    file=open(filename,'w+',encoding='utf-8') 
    # 'w+'兼备写入和读取功能
    file.write('你好啊') # 写入完成,指针在最后
    file.seek(0) # 把指针置于最前端
    # 读取
    s=file.readlines() # 读取所有行数据
    print(type(s),s)
    file.close()

if __name__ == '__main__':
    my_read('d.txt')

1.2.3.6 通过移动指针读取部分内容(第5行)

def my_read(filename):
    file=open(filename,'w+',encoding='utf-8') 
    # 'w+'兼备写入和读取功能
    file.write('你好啊') # 写入完成,指针在最后
    file.seek(3) # 把指针置于第一个字后,即3个字节后
    s=file.read()
    print(type(s),s)
    file.close()

if __name__ == '__main__':
    my_read('d.txt')

1.2.4 例11.4:文件复制(图片为例)

def copy(src,npath):
    # 文件的复制就是“边读边写”操作
    file1=open(src,'rb')
    file2=open(npath,'wb')
    s=file1.read() # 先读取file1,把s赋值为file1
    file2.write(s) # 执行写入操作,把s写入file2
    file2.close()
    file1.close() # 先打开的后关闭,后打开的先关闭
    
if __name__ == '__main__':
    src='./arc.png' # “./”一点一杠代表当前路径
    npath='../chap/copy_arc.png' # “../”两点一杠代表上级目录,即等效于后退一步
    copy(src,npath)
    print('文件复制完毕')

1.3 文件的状态和操作过程

  • 存储状态:文件在磁盘上未被打开的状态。
  • 占用状态:文件被open() 打开后进入占用状态,此时文件不允许其他程序进行操作,需要close() 将其关闭才能回到可操作状态。

2 with语句

2.1 定义

又称上下文管理器(context manager),在处理文件时,无论是否产生异常,都能保证with语句执行完毕后关闭已经打开的文件,这个过程是自动的,无需手动操作。

2.2 语法结构

with open(...)as file:
    pass

2.3 例11.5:with语句

def write_fun():
    # 打开文件 aa.txt 以写入模式,并确保在操作完成后关闭文件
    with open('aa.txt', 'w', encoding='utf-8') as file:
        # 写入内容到文件
        file.write('2022北京冬奥会欢迎您')

def read_fun():
    # 打开文件 aa.txt 以读取模式,并确保在操作完成后关闭文件
    with open('aa.txt', 'r', encoding='utf-8') as file:
        # 读取文件内容并打印
        print(file.read())

def copy(src_file, target_file):
    # 打开源文件以读取模式,并确保在操作完成后关闭文件
    with open(src_file, 'r', encoding='utf-8') as file:
        # 打开目标文件以写入模式,并确保在操作完成后关闭文件
        with open(target_file, 'w', encoding='utf-8') as file2:
            # 读取源文件内容并写入目标文件
            file2.write(file.read())

if __name__ == '__main__':
    # 调用写入函数
    write_fun()
    # 调用读取函数
    read_fun()
    # 调用复制函数
    copy('./aa.txt', './dd.txt')

3 数据的组织维度及存储

3.1 定义

  • 数据的组织维度,也称为数据的组织方式或存储方式,在Python中常用的数据组织方式可分为一维数据、二维数据和高维数据
  • 一维数据:通常采用线性方式组织数据,一般使用Python中的列表、元组或者集合进行数据的存储。
  • 二维数据:也称表格数据,由行和列组成,类似于Excel表格,在Python中使用二维列表进行存储。
  • 高维数据:使用键值对(key-value pair)方式组织数据,并借助字典形式存储。在Python中内置的json模块专门用来处理JSON(JavaScript Object Notation)格式的数据。

3.2 高维数据JSON模块的常用函数

函数名称说明
json.dumps(obj)将Python数据类型转成JSON格式过程,编码过程
json.loads(s)将JSON格式字符串转成Python数据类型,解码过程
json.dump(obj,file)dumps()功能相同,将转换结果存储到file中
json.load(file)loads()功能相同,从file中读入数据

3.3 例11.6:一维和二维数据的存储

def my_write():
    # 定义一个包含一维数据的列表
    lst = ['adx', 'wmc', 2024, 39]
    # 打开文件 'mai.csv' 以写模式 ('w') 打开,如果文件不存在将创建文件
    with open('mai.csv', 'w') as file1:
        # 使用 join() 方法将列表元素转换为字符串,并用逗号连接每个元素
        file1.write(','.join(lst)) 
        # join() 用于将列表元素转为字符串,用逗号拼接元素

def my_read():
    # 打开文件 'mai.csv' 以读模式 ('r') 打开
    with open('mai.csv', 'r') as file1:
        # 读取文件内容并存储到字符串变量 s 中
        s = file1.read()
        # 使用 split() 方法将字符串转换为列表,分隔符为逗号
        lst = s.split(',')
        # 打印列表
        print(lst)

# 存储和读取二维数据
def my_write_table():
    # 定义一个包含二维数据的列表
    lst = [
        ['商品名', '单价', '采购数量'],
        ['adx controller', '10888', '1'],
        ['yuangeki', '1500', '2']
    ]
    # 打开文件 'wmcshopping.csv' 以写模式 ('w') 打开,并指定编码为 'utf-8'
    with open('wmcshopping.csv', 'w', encoding='utf-8') as file2:
        # 遍历列表中的每个子列表
        for item in lst:
            # 使用 join() 方法将子列表元素转换为字符串,并用逗号连接每个元素
            line = ','.join(item)
            # 将转换后的字符串写入文件
            file2.write(line)
            # 写入换行符,以分隔每一行数据
            file2.write('\n')
            
def my_read_table():
    # 定义一个空列表,用于存储读取的数据
    data = []
    # 打开文件 'wmcshopping.csv' 以读模式 ('r') 打开,并指定编码为 'utf-8'
    with open('wmcshopping.csv', 'r', encoding='utf-8') as file2:
        # 使用 readlines() 方法读取文件的每一行,并返回一个列表,其中每个元素为文件的一行
        lst = file2.readlines()
        # 遍历每一行数据
        for item in lst:
            # 使用切片操作移除每行末尾的换行符,并使用 split() 方法将字符串转换为列表,分隔符为逗号
            new_lst = item[:len(item)-1:].split(',')
            # 将转换后的列表添加到 data 列表中
            data.append(new_lst)
    # 打印存储的二维数据
    print(data)

if __name__ == '__main__':
    # 调用 my_write() 函数
    # my_write()
    # 调用 my_read() 函数
    # my_read()
    # 调用 my_write_table() 函数
    # my_write_table()
    # 调用 my_read_table() 函数
    my_read_table()

3.4 例11.7:高维数据的存储

import json
# 准备高维数据
lst=[
    {'name':'Leo','age':21,'score':3.89},
    {'name':'Hazel','age':21,'score':3.93},
    {'name':'Karen','age':21,'score':3.87}
]

s=json.dumps(lst,ensure_ascii=False,indent=4)
# ensure_ascii用以正常显示字符,indent为缩进,增强JSON字符串可读性
print(type(s)) # 编码:list-->str
print(s)

# 解码:str-->list
lst2=json.loads(s)
print(type(lst2))
print(lst2)

# 编码到文件中
with open('student.txt','w') as file1:
    json.dump(lst,file1,ensure_ascii=False,indent=4)
    
# 解码到程序
with open('student.txt','r') as file1:
    lst3=json.load(file1)
    print(type(lst3),lst3)

4 目录与文件的相关操作

4.1 OS模块

OS模块是Python内置的与操作系统文件相关的模块,该模块中语句的执行结果通常与操作系统相关,即运行环境的差异(如Windows和MacOS)可能导致结果存在差异。

4.1.1 常用函数

函数名称说明
getcwd()获取当前工作路径
listdir(path)获取path路径下的文件和目录信息 如无指定path,则获取当前路径下的文件和目录信息
mkdir(path)在指定路径下创建目录(文件夹)
makedirs(path)创建多级目录
rmdir(path)删除path下的空目录
removedirs(path)删除多级目录
chdir(path)把path设置为当前目录
walk(path)遍历目录树,结果为元组,包含所有路径名、所有目录列表和文件列表
remove(path)删除path指定的文件
rename(a,b)将a重命名为b
stat(path)获取path指定的文件信息
startfule(path)启动path指定的文件

4.1.2 例11.8:OS模块的使用:创建目录/删除目录/改变工作路径/遍历目录树

import os
print('current path:',os.getcwd())
lst=os.listdir()
print('all directories and files in current path:',lst)
print('all directories and files in specific path:',os.listdir('D:/'))

# 创建目录
os.mkdir('folder1')
# 若当前路径下已存在同名目录,则报错(FileExistError: [WinError 183])

# 创建多级目录
os.makedirs('./f1/f2/f3')

# 删除空目录
os.rmdir('folder1')
# 同样效果:os.rmdir('./folder1')
# 若重复执行或文件夹不存在,会报错FileNotFoundError: [WinError 2]
os.removedirs('./f1/f2/f3') # 删除多级目录

# 改变当前路径
print('current path:',os.getcwd())
os.chdir('D:/')
print('current path (changed):',os.getcwd())
# python文件路径没变,程序运行路径发生改变

# walk()遍历目录树:递归操作
for dirs,dirlst,filelst in os.walk('D:/'):
    print(dirs)
    print(dirlst)
    print(filelst)
    print('-'*20)

4.1.3 例11.9:OS模块的高级操作:删除文件/重命名文件/查看文件信息/启动文件

import os
# 删除文件
os.remove('./a.txt')
# 若重复执行或文件不存在,会报错FileNotFoundError: [WinError 2]

# 重命名文件
os.rename('./aa.txt','./new_aa.txt')
# 若重复执行或文件不存在,会报错FileNotFoundError: [WinError 2]

# 查看文件信息
import time # 转换时间信息
def date_form(longtime):
    s=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(longtime))
    return s
info=os.stat('./new_aa.txt')
print(type(info),info)
print('last time to visit this file:',date_form(info.st_atime))
print('last time to modify this file:',date_form(info.st_mtime))
print('creation time in Win system:',date_form(info.st_ctime))
print('storage of this file:',date_form(info.st_size),'B')

# 启动路径下的文件
os.startfile('calc.exe') # 打开计算器(效果视同Win+R)
os.startfile(r"C:\Users\23608\AppData\Local\Programs\Python\Python311\python.exe") # 前写r避免Python识别路径中的右斜杠为转义字符

4.2 os.path模块

os.path模块是OS模块的子模块,也提供了一些目录或文件的操作函数。

4.2.1 常用函数

函数名称说明
abspath(path)获取目录或文件的绝对路径
exists(path)判断目录或文件在磁盘上是否存在,结果为布尔类型 若存在结果为True,反之为False
join(path,name)将目录与目录名或文件名进行拼接,相当于字符串的“+”操作
splitext()分别获取文件名和后缀名
basename(path)从path中提取文件名
dirname(path)从path中提取路径(不包含文件名)
isdir(path)判断path是否为有效路径
isfile(path)判断file是否为有效文件

4.2.2 例11.10:os.path模块的使用

import os.path

# 获取绝对路径
print('absolute path:', os.path.abspath('./b.txt'))
# 解释:os.path.abspath() 返回指定路径的绝对路径。

# 判断文件是否存在
print('if "b.txt" exists:', os.path.exists('./b.txt'))
print('if "new_b.txt" exists:', os.path.exists('./new_b.txt'))
# 解释:os.path.exists() 检查指定路径是否存在。

# 判断目录是否存在
print('if "folder1" exists:', os.path.exists('./folder1'))
# 解释:os.path.exists() 也可以用于检查目录是否存在。

# 拼接路径
print('complete path:', os.path.join('D:/', 'b.txt'))
# 解释:os.path.join() 将多个路径组合成一个路径。

# 分割文件名和后缀名
print('split name and suffix:', os.path.splitext('b.txt'))
# 解释:os.path.splitext() 将文件名和扩展名分开,返回一个元组。

# 提取文件名/路径
print('extract file name:', os.path.basename('D:/b.txt'))
print('extract file directory:', os.path.dirname('D:/b.txt'))
# 解释:os.path.basename() 提取路径中的文件名,
#       os.path.dirname() 提取路径中的目录名。

# 验证路径/文件有效性
print('validity of a directory:', os.path.isdir('D:/'))
print('validity of a file:', os.path.isfile('D:/b.txt'))
# 解释:os.path.isdir() 检查路径是否是一个目录,
#       os.path.isfile() 检查路径是否是一个文件。
最后修改:2024 年 07 月 03 日
喵~