Python:Day5:python文件操作
文件操作
一 介绍
计算机系统分为:计算机硬件,操作系统,应用程序三部分。
我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所周知,应用程序是无法直接操作硬件的,这就用到了操作系统。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。
有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:
#1. 打开文件,得到文件句柄并赋值给一个变量 #2. 通过句柄对文件进行操作 #3. 关闭文件
二 在python中
#1. 打开文件,得到文件句柄并赋值给一个变量 f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r #2. 通过句柄对文件进行操作 data=f.read() #3. 关闭文件 f.close()
三 f=open('a.txt','r')的过程分析
#1、由应用程序向操作系统发起系统调用open(...) #2、操作系统打开该文件,并返回一个文件句柄给应用程序 #3、应用程序将文件句柄赋值给变量f
四 强调!!!
with方法打开文件不用close()见下:
1 #强调第一点: 2 打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为: 3 1、f.close() #回收操作系统级打开的文件 4 2、del f #回收应用程序级的变量 5 6 其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源, 7 而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close() 8 9 虽然我这么说,但是很多同学还是会很不要脸地忘记f.close(),对于这些不长脑子的同学,我们推荐傻瓜式操作方式:使用with关键字来帮我们管理上下文 10 with open('a.txt','w') as f: 11 pass 12 13 with open('a.txt','r') as read_f,open('b.txt','w') as write_f: 14 data=read_f.read() 15 write_f.write(data)
1 #强调第二点: 2 f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。 3 这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。 4 5 f=open('a.txt','r',encoding='utf-8')
五 python2中的file与open
#首先在python3中操作文件只有一种选择,那就是open() #而在python2中则有两种方式:file()与open() 两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file
打开文件的模式
文件句柄 = open('文件路径', '模式')
模式可以是以下方式以及他们之间的组合:
#1. 打开文件的模式有(默认为文本模式): r,只读模式【默认模式,文件必须存在,不存在则抛出异常】 w,只写模式【不可读;不存在则创建;存在则清空内容】 a,只追加写模式【不可读;不存在则创建;存在则只追加内容】 #2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式) rb wb ab 注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码 #3. 了解部分 "+" 表示可以同时读写某个文件 r+, 读写【可读,可写】 w+, 写读【可读,可写】 a+, 写读【可读,可写】 x, 只写模式【不可读;不存在则创建,存在则报错】 x+ ,写读【可读,可写】 xb
1 # 回车与换行的来龙去脉 2 http://www.cnblogs.com/linhaifeng/articles/8477592.html 3 4 # U模式 5 'U' mode is deprecated and will raise an exception in future versions 6 of Python. It has no effect in Python 3. Use newline to control 7 universal newlines mode. 8 9 # 总结: 10 在python3中使用默认的newline=None即可,换行符无论何种平台统一用\n即可
操作文件的方法
#掌握 f.read() #读取所有内容,光标移动到文件末尾 f.readline() #读取一行内容,光标移动到第二行首部 f.readlines() #读取每一行内容,存放于列表中 f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符 f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符 f.writelines(['333\n','444\n']) #文件模式 f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式 #了解 f.readable() #文件是否可读 f.writable() #文件是否可读 f.closed #文件是否关闭 f.encoding #如果文件打开模式为b,则没有该属性 f.flush() #立刻将文件内容从内存刷到硬盘 f.name
练习,利用b模式,编写一个cp工具,要求如下:
1. 既可以拷贝文本又可以拷贝视频,图片等文件
2. 用户一旦参数错误,打印命令的正确使用方法,如usage: cp source_file target_file
提示:可以用import sys,然后用sys.argv获取脚本后面跟的参数
1 import sys 2 if len(sys.argv) != 3: 3 print('usage: cp source_file target_file') 4 sys.exit() 5 6 source_file,target_file=sys.argv[1],sys.argv[2] 7 with open(source_file,'rb') as read_f,open(target_file,'wb') as write_f: 8 for line in read_f: 9 write_f.write(line)
文件内光标移动
一: read(3):
1. 文件打开方式为文本模式时,代表读取3个字符
2. 文件打开方式为b模式时,代表读取3个字节
二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate
注意:
1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的
2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
1 import time 2 with open('test.txt','rb') as f: 3 f.seek(0,2) 4 while True: 5 line=f.readline() 6 if line: 7 print(line.decode('utf-8')) 8 else: 9 time.sleep(0.2)
文件的修改
文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: data=read_f.read() #全部读入内存,如果文件很大,会很卡 data=data.replace('alex','SB') #在内存中完成修改 write_f.write(data) #一次性写入新文件 os.remove('a.txt') os.rename('.a.txt.swap','a.txt')
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: for line in read_f: line=line.replace('alex','SB') write_f.write(line) os.remove('a.txt') os.rename('.a.txt.swap','a.txt')
练习题:
1. 文件a.txt内容:每一行内容分别为商品名字,价钱,个数,求出本次购物花费的总钱数 apple 10 3 tesla 100000 1 mac 3000 2 lenovo 30000 3 chicken 10 3 2. 修改文件内容,把文件中的alex换成sb
# 1.函数中return的作用 '''将函数的运行结果返回给调用的对象。''' # 2.函数中如果有多个return,会是什么效果 '''只执行满足其判定条件的的一个return在本函数中其后面的代码将不再执行''' # 3.定义一个函数max1,接受的参数类型是数值,最终返回两个数中的最大值 def max1(*args): list =[] for i in args: list.append(i) print(list) result= max(list) print(result) max1(2,4,6,8,12,) print('分割线'.center(50,'-')) # 4.定义一个函数min,接受的参数类型是数值,最终返回两个数中的最小值 def min1(*args): list=[] for i in args: list.append(i) print(list) result = min(list) print(result) min1(2,8,6,7,3,4,9,1,) print('分割线'.center(50,'*')) # 5.定义一个函数add_two 求两个数的和 def add_two(*args): result = 0 for i in args: result += i print(result) return result add_two(2,3) print('分割线'.center(50,'-')) # 6.定义一个函数add_three 在上一题的基础上求三个数的和 def add_three(*args): result = 0 for i in args: result+=i print(result) add_three(2,3,9,) print('分割线'.center(50,'*')) # 7.将人数平均随机分配到办公室 ''' import random def people(p_lists,n): print(p_lists) o_lists = [[] for i in range(n)] print(o_lists) while len(p_lists)>0: ret = len(o_lists) for i in range(ret): if len(p_lists)>0: peo = random.choice(p_lists) o_lists[i].append(peo) print(o_lists) p_lists.remove(peo) print(p_lists) else: break print(o_lists) return o_lists p = ['张三', '李四', '王五', '赵六', '陈二狗', '徐发财', '唐倒霉', '派大星', '可爱迷', '范无救', '谢必安'] o= 3 people(p,o) print('分割线'.center(50,'-')) ''' # 8.完成一个小型的计算器 计算连个数的加减乘除 def jisuan(a,b,c): if c == "+": return a + b elif c == "-": return a - b elif c == "*": return a * b elif c == "/": return a / b print(jisuan(10, 5, "*")) # 9.完成一个函数,给定三个值。判断你给的值是否可以组成一个三角形(两边之和大于第三边) def sanjia(a,b,c): if a + b -c > 0 and a + c - b > 0 and b +c -a > 0: return "ok" else: return "no" print(sanjia(10, 15, 14)) # 10.(选做题,这个题难度有点大) # 定义函数findall,实现对字符串find方法的进一步封装,要求返回符合要求的所有位置的起始下标, # 如字符串"helloworldhellopythonhelloc++hellojava",需要找出里面所有的"hello"的位置, # 最后将返回一个元组(0,10,21,29),即将h的下标全部返回出来,而find方法只能返回第一个 def findall(str,s): ret = [] len(s) if s == '': return ret while True: index = str.find(s) if index != -1: if len(ret) != 0: ret.append(index+len(s)+ret[-1]) else: ret.append(index) str = str[index+len(s):] else: break return tuple(ret) str1 = 'helloworldhellopythonhelloc++hellojava' s1 = 'h' print(findall(str1,s1)) # def findall(string,s): # ret = [] # n = len(s) # if s=='': # return ret # while True: # index = string.find(s) # if index !=-1: # if len(ret)!=0: # ret.append(n+index+ret[-1]) # else: # ret.append(index) # string = string[index+len(s):] # else: # break # return tuple(ret) # str1 = 'helloworldhellopythonhelloc++hellojava' # s1 = 'h' # print(findall(str1,s1)) # def findall(string, s): # ret = [] # n = len(s) # if s=='': # return ret # while True: # index = string.find(s) # if index != -1: # if len(ret)!=0: # ret.append(ret[-1]+index+n) # else: # ret.append(index) # string = string[index+len(s):] # else: # break # return tuple(ret) # str1 = 'helloworldhellopythonhelloc++hellojava' # s1 = 'l' # print(findall(str1,s1)) import string def count_letter(str): '''求字符串中字母的数量''' n = 0 for i in str: # 方法一 if i.isalpha(): n+=1 else: continue # 方法二 # string.ascii_letters # string.ascii_uppercase def count_blank(): '''求字符串中空格的数量''' pass def count_figure(): '''求字符串中数字的数量''' pass
""" f= open('兰亭集序2.txt','w',encoding='utf8') f.write('''《兰亭集序》 作者:王羲之 永和九年,岁在癸丑,暮春之初会于会稽山阴只兰亭,俢禊事也。 群贤毕至,少长咸集。 此地有崇山峻岭,茂林修竹,又有清水流急湍,映带左右,引以为流觞曲水,列坐其次。 虽无丝竹管弦之盛,一觞一咏,亦足 以畅叙幽情。 是日也,天朗气清,惠风和畅。仰观宇宙之大,俯察品类之盛,所以游目骋怀,足以极视听之娱,信可乐也。 夫人之相与,俯仰一世。 或取著怀抱,悟言一世之内; 或因寄锁托,放浪形骸之外。 虽趣舍万殊,静噪不同。 当其欣于所遇,暂得于已,快然自足,不知老之将至; 及其所之既倦,情随事迁,感慨系之矣。 当其欣于所遇,暂得于已,快然自足,不知老之将至;及其所之既倦,情随事迁,感慨系之矣。 向之所欣,俯仰之间,已为陈迹,犹不能不以之兴怀,况修短所化,终期于尽! 古人云:“生死亦大矣。”岂不痛哉! 每览昔人兴感之由,若合一契,未尝不临文嗟悼,不能喻之余怀。 固知—死生为虚诞,齐彭殇为妄作。 后之视今,亦犹今之视昔,悲夫! 故列叙时人,录其所属,虽世殊事异,所以兴怀,其致一也。 后之览者,亦将有感于斯文。''') f.close() """ ''' f=open('兰亭集序2.txt','r',encoding='utf8') # f=open('兰亭集序2.txt',encoding='utf8') 'r' 模式打开可以简写。 content1 = f.read(6) # 读6个字符 content2 = f.readlines() # 把读出来的按照行数放到列表对象中,需要for循环读(需要读的行数) content3 = f.read() # 接着上一次读的位置读完 # print(content1) print('_'*50) # print(content2) # for i in content2: # print(i) print('_'*50) # print(content3) f.close() ''' """ # 文件备份实例: old_file_name = input('请输入你要复制的文件名称:') index = old_file_name.rfind('.') PR_file_name = old_file_name[:index] SF_file_name = old_file_name[index:] new_file_name = PR_file_name + '[副本]'+SF_file_name f_old = open(old_file_name,'rb') f_new = open(new_file_name,'wb') while True: file = f_old.read(1024) if len(file) == 0: break f_new.write(file) f_old.close() f_new.close() """ ''' # 批量改文件名称 import os ret = os.listdir() print(os.listdir()) flag =2 for i in ret: if flag==1: os.rename(i,'[备份]-'+i) elif flag==2: num = len('[备份]-') new_name = i[num:] os.rename(i,new_name) ''' """ # 批量复制目录下的所有文件 import os # 定义一个改名字的函数 def redo_name(a): num = a.rfind('.') return a[:num] + '副本' + a[num:] # 定义一个复制文件的函数 def copy_file(b, func): f1 = open(b, 'rb') f2 = open(func, 'wb') while True: msg = f1.read(1024) if len(msg) == 0: break f2.write(msg) f1.close() f2.close() return print('复制完成') file_list = os.listdir() file_list = tuple(file_list) for i in file_list: redo_name(i) copy_file(i, redo_name(i)) # 老师的方法 # import os # # # 获取指定路径的所有文件名字 # dirList = os.listdir() # funFlag = 0 # # 遍历输出所有文件名字 # for name in dirList: # if funFlag == 1: # # 以读的方式打开文件 # oldFile = open(name, 'rb') # # 提取文件的后缀 # fileFlagNum = name.rfind('.') # if fileFlagNum > 0: # fileFlag = name[fileFlagNum:] # # 组织新的文件名字 # newFileName = name[:fileFlagNum] + '[复件]' + fileFlag # # 创建新文件 # newFile = open(newFileName, 'wb') # # 把旧文件中的数据,一行一行的进行复制到新文件中 # for lineContent in oldFile.readlines(): # newFile.write(lineContent) # # elif funFlag == 0: # fileFlagNum = name.rfind('.') # length = len("[复件]") # if fileFlagNum > 0: # fileFlag = name[:fileFlagNum] # if fileFlag[-length:] == "[复件]": # os.remove(name) """
Victor

浙公网安备 33010602011771号