【Python基础篇】【16.文件与深浅拷贝】(附案例,源码)文件夹及目录操作
2023-12-17 18:29:18
Python文件与深浅拷贝
八、文件与深浅拷贝
文件
为了保存数据,方便修改和分享,数据通常以文件的形式存储在磁盘等外部存储介质中。根据逻辑上编码不同可将文件大致分为两类:文本文件和二进制文件
文件是指为了重复使用或长期使用的目的,以文本或二进制形式存放于外部存储器(硬盘、U盘、光盘等)中的数据保存形式,文件是信息交换的重要途径,也是利用程序解决实际问题的重要媒介
- 程序对数据读取和处理都是在内存中进行的,程序设计结束或关闭后,内存中的这些数据也会随之消失。计算机文件可以将数据长期存储下来反复使用,不会因程序结束或断电而消失
- 程序可以随时读取文件里的全部或部分数据,数据的处理结果写入文件后,可以长期保存,供其他程序的应用随时读取和处理。而且,文件的使用,还可以消除计算机内存对数据体积的限制,可以处理远超过内存大小的数据量
打开文件
# open() 函数
"""
file参数 : 就是操作文件的位置(文件在电脑种保存的路径)
绝对路径 : 从盘符的根目录开始指定的文件路径 D:\qd\qd1
相对路径: 相对于当前编辑的py文件来说
mode: 文件操作的模式 指定你需要用什么方式操作这个文件
w write 写入模式
a append 写入,追加写入
r read 读取
b binary 二进制数据操作模式<图片/视频/音频> wb rb
encoding :文件的编码
window : gbk utf-8
mac : uft-8
"""
# 1. 打开文件
# w 没有就会被创建
# 通过绝对路径创建文件
f = open(file='D:\\qd\\qd1\\kk.txt',mode='w') #为了防止路径有特殊字符报错 最好多加一个\
# 通过相对路径来创建文件
f1 = open(file='kk.txt',mode='w')
# 2. 进行操作
# w 写入
f1.write('666')
f1.write(111) #是数值类型不是字符串,所以报错
# 不同模式只支持单一操作
print(f1.read())
# open函数的文件操作只能写入两种类型的数据: str / 二进制数据
# 3. 关闭 (数据有可能会泄露)
f1.close()
''' 操作模式 '''
# mode: 文件操作的模式指定你需要用什么方式操作这个文件
# w write 写入模式
# a append 写入,追加写入
# r read 读取
# b binary 二进制数据操作模式<图片/视频/音频> wb rb
""" w模式 """
f = open(file='k1.txt', mode='w') # w 写入模式如果文件不存在则自动创建
print(f) # 返回的是一个对象
f.write('777')
f.write('999') # 每一次的w写入会把原有的数据覆盖
print(f.read()) # 如果是w 那么当前这个对象只支持写入,不支持读,只能进行写入操作
f.close()
# w+
f = open(file='k5.txt', mode='w+', encoding='utf-8') # 文件不存在会被创建
f.write('666') # 默认光标会在最后
f.seek(0) # 需要先把光标移动到最前面在读
print(f.read())
""" a模式 """ # 追加写入
# a append 写入,追加写入
f = open(file='k2.txt', mode='a') # 如果文件不存在就会创建
f.write('776')
f.write('999') # 追加写入,不会被覆盖
# 关闭文件
f.close()
# a+
f = open(file='k6.txt', mode='a+', encoding='utf-8') # 文件不存在会被创建
f.write('888') # 光标默认到最后 追加写入
f.seek(0) # 需要先把光标移动到最前面在读
print(f.read())
""" r模式 """
f = open(file='k2.txt', mode='r') # 如果文件不存在则报错
print(f.read()) # 读取文件的内容
f.write('666') # 每个模式都会限制自己的功能
# 关闭文件
f.close()
# r+
f = open(file='k5.txt', mode='r+', encoding='utf-8') # 文件不存在会报错
print(f.read())
f.write('999') # 覆盖写入(是和光标位置有关系的)
f.seek(0) # 需要先把光标移动到最前面在读
print(f.read())
'''
总结:
w 和 a 模式 - 如果文件不存在则创建该文件;如果文件存在,`w` 模式先清空再写入,`a`模式直接末尾追加
r 模式 - 如果文件不存在则报错
'''
打开模式
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
读取文件
''' rand '''
# 表示要从文件中读取的数据的长度(单位是字节),如果没有传入参数,那么就表示读取文件中所有的数据
f = open(file='k2.txt', mode='r', encoding='utf-8') # 读取中文要指定编码
print(f.read()) # 默认读取全部内容
print(f.read(6)) # 如果在 read 方法中指定整型数字, 那么是按照字符数量读取数据
print(f.read(12)) # 如果超出字符数量 那么会返回所有数据
f.close()
''' randlines '''
# readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素
f = open(file='k2.txt', mode='r', encoding='utf-8')
print(f.readlines()) # 会把每一行数据和换行符进行读取,并且返回一个列表
# 比如第一行是9个字符 你如果输入的字符数小于9 那么他是会默认返回整个一行的
print(f.readlines(9))
# 如果读取到第一行的换行符那么他会默认的读取第二行,以此类推
''' readine '''
# readline() 一次读取一行内容
f = open(file='k2.txt', mode='r', encoding='utf-8')
print(f.readline()) # 默认返回第一行数据 每一次只会默认读一行
print(f.readline(15)) # 每一次只会默认读一行 参数也是读取字符数量,如果参数超过一行的字符数,那么就会把一行整个返回
print(f.readline())
print(f.readline())
while True:
txt = f.readline()
if txt: # 如果有内容返回True
print(txt)
else:
break
f.close()
with管理文件
# 文件操作, 打开文件操作完后都需要关闭文件, 比较麻烦。 with open 默认关闭文件
# with open 是有自己的专属代码块的
with open(file='k9.txt', mode='w', encoding='utf-8') as f:
f.write('888')
二进制数据
import requests
response = requests.get('https://img2.baidu.com/it/u=2565082302,1715584895&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500')
img_rr = response.content # 返回一个二进制数据
print(img_rr)
# 图片/视频/音频 都属于二进制数据
# 二进制数据不支持编码
with open('二哈.png', mode='wb') as f:
f.write(img_rr)
文件夹及目录操作 - OS
在日常使用计算机时,经常需要列出一个文件夹或者目录的内容,创建和删除文件,以及做其他一些比较无聊但是不得不做的“家务活”。在 Python 程序中可以做到同样的事,甚至能做更多的事。这些功能是否能减少你的工作量呢?我们拭目以待。
Python 在模块 os
(操作系统,operating system)中提供了许多系统函数,本章的所有程序都需要导入这个模块。
Python 的 os 模块封装了常见的文件和目录操作,本文只列出部分常用的方法,更多的方法可以查看官方文档。
os 目录操作
方法 | 说明 |
---|---|
os.mkdir | 创建目录 |
os.rmdir | 删除目录 |
os.rename | 重命名 |
os.remove | 删除文件 |
os.getcwd | 获取当前工作路径 |
os.chdir | 修改当前工作目录 |
os.path 路径操作
方法 | 说明 |
---|---|
os.path.join | 连接目录与文件名 |
os.path.split | 分割文件名与目录 |
os.path.abspath | 获取绝对路径 |
os.path.dirname | 获取路径 |
os.path.basename | 获取文件名或文件夹名 |
os.path.splitext | 分离文件名与扩展名 |
os.path.isfile | 判断给出的路径是否是一个文件 |
os.path.isdir | 判断给出的路径是否是一个目录 |
os.path.exists | 检查文件是否存在 |
import os # 模块要先导入后使用
# 创建目录 文件夹
name = 'kk'
os.mkdir(name) # 如果文件夹存在要创建就会报错
# 删除文件夹 # 如果文件夹不存在就会报错 如果文件夹里面有文件那么会报错
os.rmdir(name) # 只能删除一个空的文件夹
# 删除文件
os.remove('kk\\t1.txt') # 如果文件不存在就会报错
# 重命名, 可以针对文件/文件夹
# 针对文件夹
os.rename('kk', 'ii') # 如果文件不存在就会报错
# 针对文件
os.rename('二哈.png', '小二哈.jpg') # 如果文件不存在就会报错
''' 获取工作目录 '''
print(os.getcwd()) # 返回的是一个绝对路径
# 需求 :我现在要在当前创建一个kk3.txt的文件,还要写入555
result = os.getcwd() + '\\' + 'kk3.txt'
# 利用w模式不存在则自己创建的性质
with open(file=result, mode='w', encoding='utf-8') as f:
f.write('555') # 只支持str\二进制
''' 修改工作目录 '''
print('当前默认的工作目录:', os.getcwd())
os.chdir('ii') # 以相对路径的方式修改工作目录
print('当前默认的工作目录:', os.getcwd())
''' 列举所有文件和文件名 '''
# 列出目录下所有的内容(文件、文件夹) 返回的是一个列表
a = os.listdir('ii') # 绝对路径和相对路径都是可以的
for i in a:
try: # 防止报错
os.remove('ii' + '\\' + i) # 只能用于删除文件
except:
os.rmdir('ii' + '\\' + i) # 只能用于删除文件夹
''' 路径的操作 '''
print('当前的绝对路径: ',os.path.abspath('.')) # 当前文件
print('当前的绝对路径: ',os.path.abspath('..')) # 上一级文件
print(__file__) # 返回的是当前文件绝对路径
print(os.path.basename(__file__)) # 返回是的当前py文件的名字
print(os.path.dirname(__file__)) # 获取绝对路径
print(os.path.splitext(__file__)) # 文件路径和尾缀分开,返回的是一个元组
''' 路径判断 '''
dirname = 'code'
# isdir 判断是否为 文件夹
print(os.path.isdir(dirname)) # 返回布尔结果
# isfile 判断是否为文件
print(os.path.isfile(dirname)) # 返回布尔结果
# os.path.exists 检查路径(文件、目录)是否存在 #返回布尔结果
print(os.path.exists('小二哈.jpg'))
print(os.path.exists('code'))
# 当文件夹不存在就创建, 存在就不管他
# 避免文件存在重复创建报错
if not os.path.exists('aaa'): # if 后面对的条件为 True 才执行下面代码
os.mkdir('aaa')
案例 - 批量命名
# 需求1: 把code文件夹所有文件重命名 Python_xxxx
# 需求2: 删除Python_ 重命名:1, 构造条件的数据 2. 书写if
import os
# 第一步:打印当前的工作目录
print(os.getcwd())
a = 2
os.chdir('code')
# print(os.getcwd())
file_name = os.listdir()
for i in file_name:
if a == 1: # 执行需求1
new_name = 'Python_' + i
else: # 执行需求2
new_name = i[7:] # 索引为7开始取值
os.rename(i, new_name)
案例 - 复制内容
# 需求 : 将模拟文件种的文件复制到另一个文件夹去,数据也要写入进去
# 文件名字后面统一加 : [复制]
import os
print(os.getcwd())
for file in os.listdir('模拟'):
print(file)
# 创建一个备用文件夹,用于存放复制的文件
if not os.path.exists('备份文件夹'): # if 后面对的条件为 True 才执行下面代码
os.mkdir('备份文件夹')
# 读取旧的数据
with open(file='模拟\\' + file, mode='r', encoding='utf-8') as f:
old_data = f.read()
print(old_data)
# 准备新的文件夹名字
old_file_name = os.path.splitext(file) # 分割文件名字
print('分割文件名字', old_file_name)
new_file_name = old_file_name[0] + '[复制]' + old_file_name[-1]
print(new_file_name)
# 把数据写入到新的文件里面去
with open(file='备份文件夹\\' + new_file_name, mode='w', encoding='utf-8') as f:
f.write(old_data)
深浅拷贝
对象引用、浅拷贝、深拷贝(拓展、难点、重点)
Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果
其实这个是由于共享内存导致的结果
拷贝:原则上就是把数据分离出来,复制其数据,并以后修改互不影响。
先看 一个非拷贝的例子
使用=赋值(对象引用)
=赋值:数据完全共享
=赋值是在内存中指向同一个对象,如果是可变(mutable)类型,比如列表,修改其中一个,另一个必定改变
如果是不可变类型 (immutable) ,比如字符串,修改了其中一个,另一个并不会变
''' 对象引用 '''
array = [1, 2, 3, 4, 5]
arr1 = array # 通过赋值的方式把对象进行了引用
# 这两个变量任然是同一对象
print(id(array))
print(id(arr1))
# 修改一个对象值,也导致另一个变量的结果也会改变
array[0] = 'a'
print(array)
print(arr1)
''' 浅拷贝 '''
# 浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)
import copy # 深浅拷贝模块,内置对象
array = [1, 2, 3, 4, 5]
# 浅拷贝会新建一个对象,区分原对象
arr1 = copy.copy(array) # 将 array 这个对象完全拷贝一份出来
print(id(array))
print(id(arr1))
''' 浅拷贝作用域 '''
array2 = [1, ['a', 'b', 'c'], 3]
arr2 = copy.copy(array2)
array2[1][0] = 100
print(array2)
print(arr2)
# 浅拷贝仅作用域一维数据,就是没有嵌套
# 如果浅拷贝数据中有嵌套数据,那么拷贝出来的内容中嵌套的数据部分任然指的是同一对象
''' 深拷贝 '''
# 深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)
# 深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享
# copy.deepcopy 深拷贝,把对象里面各个维度的数据全部拷贝一份,区分原对象
array3 = [1, ['a', 'b', 'c'], 3]
arr3 = copy.deepcopy(array3)
array3[1][0] = 100
print(array3)
print(arr3)
'''
总结:
copy.copy 浅拷贝 - 只拷贝父对象,不会拷贝对象的内部的子对象。
copy.deepcopy 深拷贝 - 拷贝对象及其子对象
'''
案例 - 判断平年和闰年
"""
判断平年闰年:
闰年的条件是: 满足其中一个条件就行
一:能被4整除,但不能被100整除的年份(例如2008是闰年,1900不是闰年)
二:能被400整除的年份(例如2000年)也是闰年。
反之都是平年。
请设计一个函数
用户输入年份,传入函数中的参数
在函数中判断输入的年份是平年还是闰年
"""
def max_year(year):
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
print(f'{year}是闰年')
else:
print(f'{year}是平年')
year = int(input('请输入你的年份:'))
max_year(year)
案例 - 深浅拷贝
"""
运行代码之后,请找出下面代码错误并且修正
提示:深浅拷贝,数据不重复
"""
import copy
data = {
'cate': '童书馆',
'sub_cate': None
}
sub_cate = ['科普百科', '儿童文学', '幼儿启蒙', '动漫卡通', '少儿英语']
all_cate = [] # 定义一个空的列表
# 在字典进行添加的时候,由于他们引用的是同一个对象,由于字典的键是相同的
# 会把前面的内容进行覆盖
for cate in sub_cate:
data['sub_cate'] = cate # 通过字典的键赋值
print(id(data))
# all_cate.append(data) # 把字典添加到空的列表里面去
# 浅拷贝,适用于一维维度
all_cate.append(copy.copy(data))
print('浅拷贝', id(copy.copy(data)))
# 深拷贝,适用于所有维度
all_cate.append(copy.deepcopy(data))
print('深拷贝', id(copy.deepcopy(data)))
# print(all_cate)
文章来源:https://blog.csdn.net/weixin_43612602/article/details/134954631
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!