Python 文件操作 全面剖析详解

文件操作基础

相关概念
流程:
	1.打开一个文件,或者创建一个新的文件
	2./写数据
	3.关闭文件

# 打开一个文件
open(file[,mode][,encoding][,errors])
file 不能省略, file用来指定文件路径,即需要打开的文件名
mode 模式
encoding 编码 ---- utf-8 , gbk
errors 参数 ignore 忽略
mode 模式: 打开的模式

r     表示以只读(字符)的方式打开文件,如果打开的文件不存在,会出现异常,如果文件存在,会打开文件,且文件的定位符放在起始位置,
rb   表示以只读二进制的方式打开文件 ,...
r+   表示以读写的方式打开文件 , ...
rb+ 表示以读写二进制的方式打开文件,....
w 表示以只写的方式打开文件,如果文件不存在,会创建新的文件,打开的时候会擦除掉原有的数据,文件的定位符放在起始位置,从开始位置开始写
wb 表示以只写二进制的方式打开文件,..
w+ 表示以读写的方式打开文件,...
wb+ 表示以读写二进制的方式打开文件
a 表示以只写的方式打开文件,如果文件不存在,会创建新的文件, 如果存在打开的时候不会擦除掉原有的数据,文件的定位符放在末尾,从定位符的开始写
ab
a+
ab+

在这里插入图片描述

# r不存在都会报错,因为它主要是读的功能;
# 会覆盖说明 定位符一定前面,而且打开会擦除原有数据;
# 不会覆盖说明在后面,追加书写,不会擦除原有数据;
文件打开方式
# 默认是GBK的解码方式
rf=open("love_letter.txt",mode="r",encoding="UTF-8",errors="ignore") # 设置UTF-8
# mode默认是“r”只读

# 读
content=rf.read() # 调用read,后会返回一个值,可接收
print(content)

# 关闭
rf.close()

rf=open("love_letter.txt",mode="rb") # 会转换成二级制

rf = open("情书3.txt",mode="r")
# 以读的形式打开文件,如果文件不存在,会出现异常
# 异常 FileNotFoundError:文件找不到,异常


wf=open(love_letter.txt,mode="w") # 打开文件时,会擦除原有数据

wf=open("love_letter2.txt",mode="w") # 以写的方式打开文件时,如果文件不存在,会创建新的文件
# w 可用来创建文件
wf.close()


af=open("love_letter.txt",mode="a")
af=open("love_letter3.txt",mode="a") # 不存在会新建文件,打开不会抹去原有的数据,起始位置在末尾开始书写

contern=af.read() # 写“a”不能读,写“a+”可以读

af.close()

 
try:
     rf=open("love_letter.txt",mode="r" # 也可直接写"r",encoding="UTF-8",errors="ignore")
     content=rf.read()
except:
     print("出现异常")
finally:
     if rf!=None:
          rf.close()
with语法:
with open("love_letter.txt",mode="r",encoding="UTF-8",errors="ignore") as rf: #as 后接自定义变量
     rf.read()

# 使用with ... as 语法打开的文件,可以不用执行close,会自动的close,但是不会自动处理异常
读的操作
rf = open("情书.txt","r",encoding="utf-8")
# 读取所有的内容
content = rf.read()

# read中有参数表示读取多少个字符
content1 = rf.read(7)

# 注意: 继续读取操作时,是接着上一次读的位置继续读,说明了光标在开始的位置
content2 = rf.read(7)

print(content1)
print(content2)
# 一行一行的读
# 默认是添加了换行,可以在后面加上.strip()
content = rf.readline().strip()

# 读下一行/读一行
content = rf.readline()

# 读取所有行,结果是列表
content = rf.readlines() # 注意加了s, readlines()
# 可用于遍历
# for line in rf.readlines()
     print(line) # 这里循环的的是列表

print(content)
# 最佳读取方式
# 循环读取这种方式是最好的,每次读取一行内容,不会产生内存溢出的问题
f = open("../def/哇擦.txt", mode="r", encoding="utf-8")
for line in f:
     print(line.strip()) # 这里循环的是文件句柄
# for 可以一行一行的处理数据
读取二进制数据:
rbf =  open("情书.txt",mode="rb" # 不需要编码)
content = rbf.read()

# 参数表示读取二进制数据的长度,单位Byte
# 一个英文字符,占一个字节, 在utf-8中一个中文占3个字节 , gbk中文占2个
content = rbf.read(8)
print(content) # 二进制数据

将二进制的数据转换成:字符串
Python decode() 方法以 encoding 指定的编码格式解码字符串。默认编码为字符串编码。
.decode(encoding='UTF-8',errors='strict') 

print(content.decode(encoding="utf-8")) #.decode(encoding="UTF-8")

rf.close()
写的操作
# 打开
# 注意 w 会先擦除掉原有数据,只要带“W”只要操作就会清空原文件
# 如果文件不存在,会自动创建文件
wf = open("情书2.txt","w",encoding="utf-8")
wf = open("情书2.txt","wb")

# a是追加
af = open("情书2.txt","a",encoding="utf-8")
# af = open("情书2.txt","a+",encoding="utf-8")

# 写入一个
wf.write("对不起,你是一个好人")
wf.write("对不起,你是一个好人".encode(encoding="utf-8")) # 写入一个二进制

# 追加
#af.write("\n对不起,你是一个好人\n")
af.write("我最爱的人是敏")


# 直接把内部缓冲区的数据立刻写入文件,不需要被动的等待缓冲区刷新写入
af.flush()

# a+
af.read()

# 关闭文件
af.close()
>>>例子:
# rb, wb, ab, bytes如果处理的是非文本文件, mode里如果有b,encoding就不能给了
f = open("c:/pdd.jpg", mode="rb") # 这里不能写encoding
e = open("e:/pdd.jpg", mode="wb")
for line in f: # 从c盘读取 line你是不知道读取了多少数据的
     e.write(line)  # 写入到e盘
f.close()
e.flush()
e.close()
# 不论你读取了多少内容,光标在哪儿,写入的时候都是在结尾写入;除非上来就写入, 这时写入光标是在开头

# 最好用的读写同时存在的模式
r+ 读写模式,先读后写
w+ 写读模式,先写后读

f = open("阿西吧", mode="r+", encoding="utf-8")
s = f.read(3) # 读取三个字符,写的时候,光标永远跳到末尾
print(s)
f.write("不养了,送人") # 在末尾写
# 先写后读,会覆盖前面的内容
f.write("葫芦娃")
s = f.read()
print(s)
s = f.read(2)
print(s)
f.write("还有何云伟")
f.close()
# w+ 很少用. 因为会清空文件中的内容
f = open("阿西吧", mode="w+", encoding="utf-8")
f.write("张云雷也要退出德云社") # 写完之后光标在最后. 读取是没有内容的
f.seek(0) # 移动光标, 移动到开头
s = f.read()
print("读取的内容是",s)
f.flush()
f.close()
# a+
f = open("阿西吧", mode="a+", encoding="utf-8")
f.write("我要加入德云社")
f.seek(0)
s = f.read()
print(s)
f.flush()
f.close()
文件的定位读写
# rf = open("情书.txt","r",encoding="utf-8")
rf = open("情书.txt","rb")
content = rf.read(5) # 读取5个字节位置
.seek()

# seek() 方法用于移动文件读取指针到指定位置。单位是 byte
# 参数1:offset 开始的偏移量,也就是代表需要移动偏移的字节数
# 参数2:shence 0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
# 只有一个参数时,默认为0,表示起始位置的偏移量

rf.seek(-2,1) # 可以为负数
rf.seek(10,0) # 结果:10
rf.seek(10,1) # 结果:15 只能在"rb"的状态下使用
rf.seek(10,2) # 结果:先读取整篇文件所有长度,再+10,只能在"rb"的状态下使用


f = open("阿西吧", mode="r", encoding="utf-8")
for line in f:
     print(line.strip())

f.seek(0) # 移动到开头

for line in f:
     print(line.strip())
f.close()


f = open("阿西吧", mode="r", encoding="utf-8")
f.seek(3) # 3byte => 1中文
s = f.read(1) # 读取一个字符
print(f.tell()) # 光标在哪儿???
f.close()

seek(偏移量, 位置)
seek(0) # 开头
seek(0,1) # 当前位置
seek(0,2) # 在末尾的偏移量是0末尾
.tell()
# 获取当前的字节位置,输出的是数值
# 字节表示
index = rf.tell()
print("index=%d"%(index))
#print(content)

rf.close()
.truncate() 截断⽂文件

f = open("啊同类个同同同", mode="w", encoding="utf-8")
f.write("哇哈哈哈哈亚索盖伦")
f.seek(9)
f.truncate() # 无参数,截断到光标位置
print(f.tell()) # 9  娃哈哈
# 默认从文件开头截断到光标位置

# 如果给参数. 从头截断到参数位置
f.truncate(12) # 娃哈哈哈
f.close()

# 所以如果想做截断操作,记住:要先挪动光标,挪动到你想要截断的位置,然后再进行截断
# 关于truncate(n), 如果给出了n,则从开头行截断;如果不给n, 则从当前光标位置截断,后面的内容将会被删除

目录操作基础

相对目录和绝对目录(文件路径)
相对目录(路径):
	同一个文件夹下的文件,相对于当前这个程序所在的文件夹而言;如果在同一个文件夹中,
则相对路径就是这个文件名,如果在上一层文件夹,则要 ../
	推荐使用相对路径,因为在将程序拷贝给别人使用的时候,直接把项目拷贝走,就能运行,
但是如果用绝对路径,那还需要拷贝外部的文件

rf = open("情书.txt","r",encoding="utf-8")

	返回上一级目录
	“../” 从当前的文件夹出来
绝对目录 --- 完整的路径(带盘符的)
rf=open(r"C:\Users\Administrator\Desktop\Communal\星座.py",mode="r",encoding="UTF-8",errors="ignore")
# 注意转义字符,在前面加上“r”

print(rf.read())

rf.close()
相关操作
os 模块包含了系统普遍的一些功能

import os

查:
# 获取当前目录的相对路径
#  . 用 点 来表示的是当前路径,  .. 来表示的是父级目录
print(os.curdir) # 结果是一个 .

rf = open(r".\test\新闻.txt","r",encoding="utf-8")
print(rf.read())
rf.close()

# 获取当前的工作路径
print(os.getcwd())

# 获取目录下所有的 目录名 和 文件名, 将所有的目录和文件名封装成一个列表
listFileName = os.listdir(r"I:\sz1704\day08\code")
print(listFileName)

增:
# 创建一个新的目录,注意:如果创建的文件已经存在,会报异常
# 绝对路径创建
os.mkdir(r"I:\sz1704\day08\news")

# 相对路径
os.mkdir(r"news")
# 注意: 还是一个目录
os.mkdir(r"news.txt") # 目录名而已

# 创建文件--> open
# mkdir创建目录时,如果该新目录的父级目录不存在,会报异常
# os.mkdir(r"I:\sz1704\day08\news\hello") 不存在,会报异常
# makedirs创建目录时,如果该新目录的父级目录不存在,会一同创建
# os.makedirs(r"I:\sz1704\day08\news\hello")

改:
# 重命名
# 相对目录
# 可以修改 文件名

参数1:表示的是原文件名,  参数2表示的是新的文件名,
# 如果原文件名对应的文件不存在,会 报异常
os.rename("情书3.txt","情书终结版.txt")
# 修改目录名
os.rename("news.txt","新闻") # 可以修改目录名

# 修改绝对路径的文件名
os.rename(r"I:\sz1704\day08\news\hello",r"I:\sz1704\day08\news\word")


删:
# 删除目录
os.rmdir("新闻")
os.rmdir(r"I:\sz1704\day08\news\word") # 也可删除绝对路径下的

# 删除文件
os.remove("情书2.txt") # 也可删除绝对路径下指定的文件

os.system("write")

文件复制与修改

文件复制
文件复制:
    0.获取源文件的文件名
    1.先创建一个(写的方式打开)副本文件
    2.打开并读取源文件的内容
    3.将源文件的内容写入副本文件
    4.关闭源文件副本文件
file_name=input("please enter needing copy file name:") # 获取到一个字符串
index=file_name.rfind(".") # 从右边开始找,参数表示找到的位置(包前),所以光标位置会到.的前面
     #.index(".")也行
# 字符串拼接
copy_name=file_name[:index]+"-副本"+file_name[index:]
# print(copy_name)

copy_file=open(copy_name,"w",encoding="utf-8") # 创建(写的方式打开)一个副本文件
     # 注意别写成"copy_name",你这样直接把别人变成字符串了!!!
# copy_file=open(copy_name,"wb") 二进制数据

source_file=open(file_name,"r",encoding="utf-8") # 以读的方式打开源文件
#source_file=open(file_name,"rb")

content=source_file.read() # 读取到源文件的内容
copy_file.write(content) # 将源文件的内容写入拷贝文件
copy_file.flush() # 推缓存

# 复制大文件的操作:让它边写边读
while True:
     content = source_file.read(1024) # 读取1024byte=1M
     if len(content) == 0: # 写完了,循环放在前面,主要用于判断是否读完
          break # 跳出循环

     copyFile.write(content) # 写入
     copyFile.flush() # 推缓存


copy_file.close() # 关闭
source_file.close()

# 优化:
file_name = input("please enter you need copy file name:")
index_dot = file_name.rfind(".")
copy_name = file_name[:index_dot] + "_副本" + file_name[index_dot:]
with open(copy_name, mode="w", encoding="utf-8") as copy_file, \
        open(file_name, mode="r", encoding="utf-8") as source_file:
    for line in source_file:
        copy_file.write(line)
        copy_file.flush()
文件修改
# 引入模块
import os
import time

# 打开目标文件
# f1 = open("你昨天干嘛去了", mode="r", encoding="utf-8")
with open("你昨天又干嘛去了", mode="r", encoding="utf-8") as f1, \
     open("你昨天又干嘛去了_副本", mode="w", encoding="utf-8") as f2:
     # 在同一行还要换行进行相同的操作,可以写,\
     for line in f1:
          line = line.replace("你", "sb")#此处进行修改操作
          f2.write(line)

time.sleep(3)
# 删除文件
os.remove("你昨天又干嘛去了")
time.sleep(3)
# 重命名文件
os.rename("你昨天又干嘛去了_副本","你昨天又干嘛去了")
# 拓展:修改方式为,在某一行添加一行新内容
import os
with open("练习修改.txt",mode="r",encoding="utf-8") as rf1 ,\
     open("练习修改_副本.txt",mode="w",encoding="utf-8") as rf2:
     for line in rf1:
          if line.strip()=="that begin!":
               rf2.write("这是在前面增加的内容\n")
          rf2.write(line)
os.remove("练习修改.txt")
os.rename("练习修改_副本.txt","练习修改.txt")
>>>实战:读取一个日志文件,将它每行以字典的方式保存,并都放入一个列表中
'''
.log文件

id,name,phone,car,home,salary
1,alex,10086,特斯拉,于辛庄,5000000
2,wusir,10010,五菱宏光,青年,400000
3,taibai,10000,魔板单车,松兰堡,30000
4,ritian,12345,小黄车,广东,30000
'''
li = []
with open("2019-6-11.log", mode="r", encoding="utf-8") as rf:
    first = rf.readline().strip().split(",")  # type(first)list 把行首的内容读取到
    for line in rf:
        dic = {}
        content = line.strip().split(",")
        for i in range(len(first)):
            dic[first[i]] = content[i]
        li.append(dic)
print(li)

# 解构,元素少的时候
'''
infor.txt
1,alex,10086
2,wusir,10010
3,taibai,10000
4,ritian,12345
'''

lis = []
with open("infor.txt", mode="r", encoding="utf-8") as rf:
    for line in rf:
        dic = {}
        a, b, c = line.strip().split(",")
        dic = {"num": a, "name": b, "phone": c}
        lis.append(dic)
>>>实战:对文件内容进行计算
'''
.txt 文件
name:apple price:10 amount:3 year:2012
name:tesla price:100000 amount:1 year:2013
'''
rf = open("eat.txt", mode="r", encoding="utf-8")
res = []
for line in rf:
    content = line.strip().split()
    dic = {}
    for re in content:
        key, value = re.strip().split(":")
        dic[key] = value
    res.append(dic)
print(res)
# [{'name': 'apple', 'price': '10', 'amount': '3', 'year': '2012'},
# {'name': 'tesla', 'price': '100000', 'amount': '1', 'year': '2013'}]

sum = 0
for li in res:
    sum = sum + int(li["price"]) * int(li["amount"])
print(sum)
# 实战:模拟用户注册和登录

user_name = input("please enter your register user name:")
user_code = input("please enter your register code:")
with open("login.txt", "w", encoding="utf-8") as wf:
    wf.write("{}\n{}".format(user_name, user_code))
    # 巧用format写入多个参数
    print("Congratulations you register succeed!")

i = 0
li = []
while i < 3:
    usn = input("please enter your user name:")
    pwd = input("plese enter your code:")
    with open("login.txt", "r+", encoding="utf-8") as rf:
        for line in rf:
            li.append(line.strip())
        if usn == li[0].strip() and li[1].strip() == pwd:
            print("login succeed!")
            break
        else:
            print("your enter username or usercode is worng!")
        if i == 2:
            print("your count is frozen!")
    i += 1

目录复制

复制目录(包括所有文件)
"""
思路:
1.定义个一个函数,参数1:指定要复制的目录 参数2:目标目录的位置
2.判断指定目录是否存在--不存在退出
3.判断目标目录是否存在--不存在,创建新的(如果你原来就创建了指定目录,就是存在喽)
4.遍历目录
     1.如果是目录,继续遍历直到是文件,且需要在目标目录中创建新的(即一层一层的目录)
     2.如果是文件,复制--读-写--文件
          1.什么情况下才复制:当文件不存在 或 文件存在,内容不同(通过文件长度)来判断
"""
import os


def copy_dir(source_path, target_path):
    if not os.path.exists(source_path):  # 判断指定目录是否存在
        return
    if not os.path.exists(target_path):  # 判断目标目录是否存在
        os.makedirs(target_path)  # 不存在,创建一个

    for file_name in os.listdir(source_path):  # 遍历目录
        abs_source_path = os.path.join(source_path, file_name)  # 源路径:拼成绝对路径
        abs_target_path = os.path.join(target_path, file_name)  # 目标路径:拼成绝对路径

        if os.path.isdir(abs_source_path):  # 如果源路径,是目录
            os.makedirs(abs_target_path)  # 给目标目录创建一层新的目录
            copy_dir(abs_source_path, abs_target_path)  # 继续遍历,这里用的是递归
        if os.path.isfile(abs_source_path):  # 如果是文件
            if (not os.path.exists(abs_target_path)) or (
                    os.path.exists(abs_target_path) and os.path.getsize(abs_source_path) != os.path.getsize(
                abs_target_path)):
                # 进行复制的条件:当文件不存在 或 文件存在,内容不同(通过文件长度)来判断
                rf = open(abs_source_path, "rb")
                wf = open(abs_target_path, "wb")
                while True:
                    content = rf.read(1024)
                    if len(content) == 0:
                        break
                    wf.write(content)
                    wf.flush()
                rf.close()
                wf.close()


if __name__ == '__main__':
    source_path = r"F:\part1\day2"
    target_path = r"F:\part1\day2副本"
    copy_dir(source_path, target_path)

练习题

>>>邮箱分类
'''
1.遍历目录
2.如果是目录接着遍历
3.如果是文件
     1.以只读的形式打开文件
     2.一行一行的读
     3.提取邮箱类型
     4.判断该类型对应的目录是否存在
         存在
         不存在---创建目录
     5.写入数据
4.关闭文件
'''
import os


# 邮箱分类
def mailType(sourcePath):
    if not os.path.exists(sourcePath):  # 判断目录是否存在
        return  # 不存在,则直接结束该函数
    # 获取该目录下所有的目录名和文件名
    listName = os.listdir(sourcePath)
    for fileDirName in listName:
        # 拼接成绝对路径
        absPath = os.path.join(sourcePath, fileDirName)
        if os.path.isdir(absPath):  # 是目录
            # print("dirPath:%s"%(absPath))
            mailType(absPath)
        # 判断
        if os.path.isfile(absPath):  # 是文件
            # print("filePath:%s" % (absPath))
            parseMailFile(absPath)  # 重新定义一个函数来处理是“文件”的情况

#解析处理邮箱文件
'''
如果是文件:
1.以只读的形式打开文件
2.一行一行的读
3.提取邮箱类型
4.判断该类型对应的目录是否存在
存在
不存在 ---创建目录
5.写
关闭文件
'''
def parseMailFile(mailFilePath):
    targetPath = r"C:\Users\wenyucheng\Desktop\资料1\作业\邮箱分类"
    with open(mailFilePath, mode="r", encoding="utf-8", errors="ignore") as rf:
        while True:
            # 一行一行的读
            lineData = rf.readline()
            if len(lineData) == 0:  # 读完了
                break
            # lineData ---> "wangchao8438293@163.com----520520"
            # lineData ---> "wangchao8438293@163.com"
            # lineData ---> "wangchao8438293@163.com"
            # @ --- @163.com.cn
            # .
            # 先拆分成邮箱和密码
            mailStr = lineData.split("----")[0]  # 拆分后,只保留前面邮箱部分
            # print(mailStr)
            # 找到 . 的位置
            dotIndex = mailStr.rfind(".")
            # 找到 @ 的位置
            aIndex = mailStr.rfind("@")  # 位置会跳到@前面
            # 获得当前邮箱的类型
            type = mailStr[aIndex + 1: dotIndex]  # @向后加一个位置;. 的位置默认不包括点,所以不需要操作
            # 判断type是否为空
            if type == None or len(type) == 0:
                continue  # 跳出本次循环,进行下次循环
                # print(type)
            # 拼接 邮箱 目录
            dirPath = os.path.join(targetPath, type)  # 在“邮箱分类下”,创建各个邮箱类型文件夹
            # 判断目录是否存在,如果不存在则创建新的目录
            if not os.path.exists(dirPath):
                os.makedirs(dirPath)
            # 拼接文件的路径
            filePath = os.path.join(dirPath, type + ".txt")
            # C:\Users\wenyucheng\Desktop\资料1\作业\邮箱分类\163.com\163.com.txt
            # 写
            with open(filePath, "a", encoding="utf-8", errors="ignore") as af:
                af.write(mailStr + "\n")
                af.flush()


if __name__ == '__main__':
    path = r"C:\Users\wenyucheng\Desktop\资料1\作业\newdir"
    mailType(path)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值