文件操作

一、文件操作

   使⽤python来读写⽂件是非常简单的操作. 我们使用open()函数来打开一个文件, 获取到⽂文 件句句柄. 然后通过⽂文件句句柄就可以进行各种各样的操作了了. 根据打开方式的不同能够执行的操 作也会有相应的差异.     打开文件的⽅方式: r, w, a, r+, w+, a+, rb, wb, ab, r+b, w+b, a+b 默认使⽤用的是r(只读)模式 

  系统对文件的各种操作:

  1,将原文件读取到内存。
  2,在内存中进行修改,形成新的内容。
  3,将新的字符串写入新文件。
  4,将原文件删除。
  5,将新文件重命名成原文件。

二、只读操作(r,rb, r+,r+b)

f = open("护⼠少妇嫩模.txt",mode="r", encoding="utf-8") 
content = f.read()       # 在这里要记住,在r模式下encoding 表示解码,在w情况下,是编码
print(content) 
f.close()

# 需要注意encoding表⽰示编码集. 根据⽂文件的实际保存编码进⾏行行获取数据, 对于我们⽽而⾔言. 更更 多的是utf-8.   
rb. 读取出来的数据是bytes类型, 在rb模式下. 不能选择encoding字符集. 但是涉及到需要解码或则编码是还是需要encoding, 


f = open("护⼠少妇嫩模.txt",mode="rb" ) 
content = f.read() 
print(content) 
f.close() 
#结果: b'xe6xafx85xe5x93xa5, xe5xa4xaaxe7x99xbd, wuse
xe5x91xb5xe5x91xb5
xe6x97xa5xe5xa4xa9'


 rb的作⽤用: 在读取非⽂本⽂件的时候. 比如读取MP3. 图像. 视频等信息的时候就需要⽤用到 rb. 因为这种数据是没办法直接显⽰示出来的.  在后⾯面我们⽂文件上传下载的时候还会⽤用到. 还有.
我们看的直播. 实际上都是这种数据.

   一般格式: f =open(’文件名(路径)', mode='模式',encoding ='编码方式')特殊格式: with open(’文件名(路径)', mode='模式',encoding ='编码方式') as f:

文件操作流程:打开一个文件(),产生一个文件句柄,对文件句柄进行操作,关闭文件

    绝对路径和相对路径:

      1. 绝对路径:从磁盘根⽬录开始⼀一直到文件名. 2. 相对路路径:同⼀个文件夹下的⽂件. 相对于当前这个程序所在的⽂件夹⽽而⾔言. 如果在同 一个⽂件夹中. 则相对路径就是这个⽂件名. 如果在上一层⽂件夹. 则要../  (更推荐大家使用相对路径,因为我们在把程序拷贝时,直接把项目拷贝过去就好,不用拷贝C盘等其他盘)

读取的方法(r,r+,rb):

  read()将文件的内容全部读取出来, 弊端:相当占内存,如果文件过大,容易导致内存崩溃

f = open("../def/哇擦.txt", mode="r", encoding="utf-8") 
content = f.read() 
print(content)   #结果: 友谊地久天长, 爱一点, 可惜我是⽔瓶座 一⽣生中最爱

read(n)可以读取n个字符,需要注意的是,如果再次读取,那么将从光标位置读取,如果是rb模式,则是读取n个字节

f = open("../def/哇擦.txt", mode="r", encoding="utf-8") 
content = f.read(3) 
content2 = f.read(3) 
print(content) 
print(content2)    # 结果: 友谊地 久天⻓长


readline() ⼀次读取⼀行数据, 注意: readline()结尾, 注意每次读取出来的数据都会有⼀ 个
 所以呢. 需要我们使⽤用strip()⽅方法来去掉
或者空格
readline(n) 当有参数n时,则时读取一行的开头的前n个字:
readlines() 将每一⾏形成一个元素, 放到⼀个列表中. 将所有的内容都读取出来. 所以 也是. 容易易出现内存崩溃的问题.不推荐使⽤,形成一个列表

我们来看看:
with open('a.txt', 'r', encoding='utf-8') as f:
    s = f.read()
    for i in s:
        print(i)     # 这个运行的结果是,文件中的每一个字符为一行,说明read的结果是生成将每一个字符添加到一个列表中

with open('a.txt', 'r', encoding='utf-8') as f:
    a = f.readlines()
    for i in a:
        print(i)      # 而这个结果是分别打印每一行的文字,说明readlines()的结果是将每一行加到一个列表中

with open('a.txt', 'r', encoding='utf-8') as f:
    s = f.read()
    for i in s:
        print(i)
    a = f.readlines()
    for i in a:
        print(i)  # 这样的结果是以每一个字符读取换行,因为当下一次循环时,光标已经在末尾了

from collections import Iterable,Iterator
print(isinstance(open('a','w'),Iterable))  #True
print(isinstance(open('a','w'),Iterator)) # True  所以文件句柄是个可迭代的,迭代器

循环读取:
f = open("../def/哇擦.txt", mode="r", encoding="utf-8") 
for line in f:    
    print(line.strip())

三、写模式(w,wb, w+b,w+):

  写的时候注意. 如果没有文件. 则会创建文件, 如果⽂件存在. 则将原件中原来的内容删除, 再 写入新内容 

f = open("⼩小娃娃", mode="w", encoding="utf-8") 
f.write("⾦⽑狮王") 
f.flush()    # 刷新. 养成好习惯 
f.close()

试试读能读吗?
f = open("⼩娃娃", mode="w", encoding="utf-8") 
f.write("金⽑狮王")
f.read()    # not readable 模式是w. 不可以执行读操作 
f.flush() 
f.close()

wb模式下. 可以不指定打开文件的编码. 但是在写文件的时候必须将字符串转化成utf-8的 bytes数据
f = open("小娃娃", mode="wb") 
f.write("⾦毛狮王".encode("utf-8"))   # 要注意再写的时候一定要写编码的格式
f.flush() 
f.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()

四、追加(a, ab, a+b,a+)

  在追加模式下. 我们写入的内容会追加在⽂件的结尾,相当于在这种模式下,打开后光标默认在尾部.

f = open("⼩小娃娃", mode="a", encoding="utf-8") 
f.write("麻花藤的最爱") 
f.flush() 
f.close()          # 正常的读取之后, 写在结尾

五、读写模式(r+,r+b)

  对于读写模式. 必须是先读. 因为默认光标是在开头的. 准备读取的. 当读完了之后再进行写入. 我们以后使⽤用频率最高的模式就是r+ 

f = open("⼩小娃娃", mode="r+", encoding="utf-8") 
content = f.read() 
f.write("麻花藤的最爱") 
print(content) 
f.flush() 
f.close()   # 结果: 正常的读取之后, 写在结尾

错误示范:
f = open("⼩小娃娃", mode="r+", encoding="utf-8") 
f.write("哈哈") 
content = f.read() 
print(content) 
f.flush() 
f.close()     # 结果: 将开头的内容改写成了了"哈哈", 然后读取的内容是后⾯面的内容,因为光标的位置

六、写读(w+ ,w+b)

  先将所有的内容清空,然后写入。最后读取,但是读取的内容时空的,不常用

f = open("⼩小娃娃", mode="w+", encoding="utf-8") 
f.write("哈哈") 
content = f.read() 
print(content) 
f.flush() 
f.close()    #  有人会说. 先读不就好了么? 错. w+ 模式下, ⼀开始读取不到数据. 然后写的时候再将原来的内容清空. 所以, 很少用. 

七、追加读(a+)

   a+模式下, 不论先读还是后读. 都是读取不到数据的. 除非seek()光标位置

f = open("⼩小娃娃", mode="a+", encoding="utf-8") 
f.write("⻢马化腾") 
content = f.read() 
print(content) 
f.flush() 
f.close()   # 还有⼀些其他的带b的操作. 就不多赘述了. 就是把字符换成字节. 仅此⽽而已

重要的方法:

  1、seek(n) 光标移动到n位置, 注意, 移动的单位是byte. 所以如果是UTF-8的中⽂部要是3的倍数. 通常我们使用seek都是移动到开头或者结尾.

  移动到开头: seek(0)

  移动到结尾: seek(0,2)

  seek的第⼆个参数表示的是从哪个位置进行偏移(初始位置), 默认是0, 表示开头, 1表⽰当前位置, 2表示结尾,seek(偏移度,位置)

  2、 tell() 使⽤用tell()可以帮我们获取到当前光标在什么位置

f = open("⼩小娃娃", mode="r+", encoding="utf-8") 
f.seek(0)   # 光标移动到开头 
content = f.read()  # 读取内容, 此时光标移动到结尾
print(content) 
f.seek(0)   # 再次将光标移动到开头 
f.seek(0, 2)    # 将光标移动到结尾 
content2 = f.read()  # 读取内容. 什什么都没有 
print(content2)
 
f.seek(0)   # 移动到开头 
f.write("张国荣")  # 写⼊入信息. 此时光标在9  中⽂文3 * 3个 = 9 
print(f.tell())  # 光标位置9 
f.flush() 
f.close()

  3. truncate() 截断⽂件  使用的是光标f = open("⼩娃娃", mode="w", encoding="utf-8"

f.write("哈哈")   # 写入两个字符 
f.seek(3)   # 光标移动到3, 也就是两个字中间 
f.truncate()    # 删掉光标后⾯面的所有内容 
f.close()

f = open("⼩小娃娃", mode="r+", encoding="utf-8") 
content = f.read(3)  # 读取12个字符 
f.seek(4) 
print(f.tell()) 
f.truncate()    # 后面的所有内容全部都删掉 
    # print(content) 
f.flush() 
f.close()
注意事项:
 
#log.txt 文件内容是‘哈哈,我是谁和谁’
f = open('log.txt',encoding='utf-8',mode='r+')
f.truncate(6)         # 运行结果是 哈哈   对文件进行修改
content = f.read()   # 这里把文件加载到内存中,读取
print(content)
f.close()
 
类似的情况却不一样:
f = open('a.txt',encoding='utf-8',mode='r+')
  # f.truncate(6)
content = f.read(3)    #把a.txt的内容全部加载到内存中,utf-8,三个字节是一个字符,读取后光标在‘哈’后面
print(content)     # 运行的结果是‘哈哈,’
f.truncate(3)         #在源文件中进行写,也就是执行后源文件变成了一个字,‘哈’,但是对加载到内存的read()没有影响
print(f.read())        #这里运行的结果是 ”我是谁和谁“ 所以不是读取truncate后的文件 ,读取的是加载在内存的文件
f.close()
 

  注意事项:

  深坑请注意: 在r+模式下. 如果读取了内容. 不论读取内容多少. 光标显示的是多少. 再写入 或者操作文件的时候都是在结尾进行的操作. 所以如果想做截断操作. 记住了. 要先挪动光标. 挪动到你想要截断的位置. 然后再进行截断 关于truncate(n), 如果给出了n. 则从开头进行截断, 如果不给n, 则从当前位置截断. 后⾯的内容将会被删除

八.修改文件以及另一种打开方式:

      ⽂文件修改: 只能将⽂文件中的内容读取到内存中, 将信息修改完毕, 然后将源⽂文件删除, 将新 ⽂文件的名字改成老⽂文件的名字. 

# 第一种修改方式:
import os
with open("⼩小娃娃", mode="r", encoding="utf-8") as f1,     
    open("⼩小娃娃_new", mode="w", encoding="UTF-8") as f2:    
         content = f1.read()    
         new_content = content.replace("冰糖葫芦", "⼤大⽩白梨梨") 

f2.write(new_content) os.remove("⼩小娃娃")    # 删除源⽂文件     os.rename("⼩小娃娃_new", "⼩小娃娃")     # 重命名新⽂文件   

#但是以上一种方法有弊端,因为其时一次性讲整个文件读入内存,若文件过大会崩溃 


#推荐以下方法:
with open("⼩小娃娃", mode="r", encoding="utf-8") as f1,     
    open("⼩小娃娃_new", mode="w", encoding="UTF-8") as f2:    
       for line in f1:        
      new_line = line.replace("⼤大⽩白梨梨", "冰糖葫芦")
        
f2.write(new_line) 
os.remove("⼩小娃娃")    # 删除源⽂文件 
os.rename("⼩小娃娃_new", "⼩小娃娃")     # 重命名新⽂文件             

 练习题:

1.文件a1.txt内容(升级题)

序号     部门      人数      平均年龄      备注
1       python    30         26         单身狗
2       Linux     26         30         没对象
3       运营部     20         24         女生多
.......

通过代码,将其构建成这种数据类型:
[{'序号':'1','部门':Python,'人数':30,'平均年龄':26,'备注':'单身狗'},
......]

l1 = []
  with open('a2.txt', encoding='utf-8') as f1:
        # 读取第一行,去除空格,使用空格切割成列表
      list_name = f1.readline().strip().split()
        # 从第二行开始读取,因为读取一行之后,光标自动移动到下面一行。
        # 所以for循环不会读取到第一行
      for i in f1:
          dic = {}
            # 去除空格,以空格切割成列表
          i = i.strip().split()
            # 遍历i
         for j in range(len(i)):
                # 添加字典, list_name[j]表示key, i[j]表示value,比如'序号': '1'
              dic[list_name[j]] = i[j]
            # 添加到列表中
          l1.append(dic)

print(l1)


2.文件a1.txt内容(升级题)

name:apple price:10 amount:3 year:2012
name:tesla price:100000 amount:1 year:2013
.......

通过代码,将其构建成这种数据类型:
[{'name':'apple','price':10,'amount':3},
{'name':'tesla','price':1000000,'amount':1}......]
并计算出总价钱。

li = []
with open('a11.txt', 'r', encoding='utf-8') as f:
    for i in f:
        a = i.strip().split(' ')
        dic = {}
        for i in a:
            b = i.split(':')
            if b[1].isdigit():
                dic[b[0]] = int(b[1])
            else:
                dic[b[0]] = b[1]

        li.append(dic)
print(li)
sum = 0
for i in range(len(li)):
    sum +=li[i]['price'] * li[i]['amount']

# print(li)
print('总计消费%d'%sum)
1、缓存机制和小数据池:
    
    不同代码块的缓存机制:
    Python在执行同一个代码块的初始化对象的命令时,会检查是否其值是否已经存在,如果存在,会将其重用。换句话说:执行同一个代码块时,遇到初始化对象的命令时,他会将初始化的这个变量与值存储在一个字典中,在遇到新的变量时,会先在字典中查询记录,如果有同样的记录那么它会重复使用这个字典中的之前的这个值。所以在你给出的例子中,文件执行时(同一个代码块)会把i1、i2两个变量指向同一个对象,满足缓存机制则他们在内存中只存在一个,即:id相同。
小数据池:
    Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。python会将一定规则的字符串在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象。其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是将~5-256的整数,和一定规则的字符串,放在一个‘池’(容器,或者字典)中,无论程序中那些变量指向这些范围内的整数或者字符串,那么他直接在这个‘池’中引用,言外之意,就是内存中之创建一个。

2、编程题:
有文件t1.txt里面的内容为:(5分)
    id,name,age,phone,job
    1,alex,22,13651054608,IT
    2,wusir,23,13304320533,Tearcher
    3,taibai,18,1333235322,IT

利用文件操作,将其构造成如下数据类型。
[{'id':'1','name':'alex','age':'22','phone':'13651054608','job':'IT'},......]

l=[]
with open('t1.txt','r',encoding = 'utf-8') as f:
    li = f.readline().strip().split(',')
    for i in f:
        lst = i.strip().split(',')
        for i in li:
            dic= dict([(li[0],lst[0]),(li[1],lst[1]),(li[2],lst[2]),(li[3],lst[3]),(li[4],lst[4])])
            l.append(dic)
print(l)

车牌区域划分,给出一下车牌和地点信息对照,请根据车牌信息,分析出各省的车牌持有数量。
    cars = ['鲁A32444', '鲁B12333', '京B8989M', '黑C49678', '黑C46555', '沪B25041', '黑C34567']
    locations = {'': '上海', '': '北京', '': '黑龙江', '': '山东', '': '湖北', '': '湖南'}(6分)
    最终形成这样的数据:{'山东': 2, '黑龙江': 3, '北京': 1, '上海': 1}

法一:
result = {}
for car in cars:
   result[locations[car[0]]] = result.get(locations[car[0]], 0) + 1
print(result)

法二:
for i in cars:
   if locations[i[0]]  not in li:
       li[locations[i[0]]] = 1
   else:li[locations[i[0]]] += 1
print(li)


按要求完成下列转化。(8分)
list3 = [
    {"name": "alex", "hobby": "抽烟"},
    {"name": "alex", "hobby": "喝酒"},
    {"name": "alex", "hobby": "烫头"},
    {"name": "alex", "hobby": "Massage"},
    {"name": "wusir", "hobby": "喊麦"},
    {"name": "wusir", "hobby": "街舞"},
]
list4 = [
    {"name": "alex", "hobby_list": ["抽烟", "喝酒", "烫头", "Massage"]},
    {"name": "wusir", "hobby_list": ["喊麦", "街舞"]},
]
将list3 这种数据类型转化成list4类型,你写的代码必须支持可拓展,
比如list3 数据在加一个这样的字典{"name": "wusir", "hobby": "溜达"},    你的list4{"name": "wusir", "hobby_list": ["喊麦", "街舞", "溜达"],
或者list3增加一个字典{"name": "太白", "hobby": "开车"},
你的list4{"name": "太白", "hobby_list": ["开车"],无论按照要求加多少数据,你的代码都可以转化.如果不支持拓展,则4分,支持拓展则8分.

list3 = [
    {"name": "alex", "hobby": "抽烟"},
    {"name": "alex", "hobby": "喝酒"},
    {"name": "alex", "hobby": "烫头"},
    {"name": "alex", "hobby": "Massage"},
    {"name": "wusir", "hobby": "喊麦"},
    {"name": "wusir", "hobby": "街舞"},
]

dic ={}
for i in list3:
    if i['name'] not in dic:
         dic[i['name']] = {'name':i['name'],'hobby_list':[i['hobby']]}
    else:
         dic[i['name']]['hobby_list'].append(i['hobby'])
list4 = list(dic.values())
print(list4)
第一次考试总结
原文地址:https://www.cnblogs.com/double-W/p/9440888.html