• Python成长之路【第五篇】:Python基础之文件处理


    一、文件操作

    1、介绍

    计算机系统分为:计算机硬件,操作系统,应用程序三部分。

    我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所周知,应用程序是无法直接操作硬件的,这就用到了操作系统。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。

    有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:

    1、打开文件,得到文件句柄并赋值给一个变量
    2、通过句柄对文件进行操作
    3、关闭文件
    

    二、在Python中

    #1. 打开文件,得到文件句柄并赋值给一个变量
    f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r,r 代表只读
    
    #2. 通过句柄对文件进行操作
    data=f.read()   # r 代表对文件进行读操作
    
    #3. 关闭文件
    f.close()
    

    三、f = open('a.txt','r') 的过程分析

    1、由应用程序向操作系统发起系统调用open(...)
    
    2、操作系统打开该文件,并返回一个文件句柄给应用程序
    
    3、应用程序将文件句柄赋值给变量 f
    

    四、强调!!!

     1 # 强调第一点:
     2 打开一个文件包含两部分资源:操作系统级打开的文件 + 应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为:
     3 1、f.close()  # 回收操作系统级打开的文件
     4 2、del f  # 回收应用程序级的变量
     5 
     6 其中del f
     7 一定要发生在f.close()之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源,
     8 而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close()
     9 
    10 虽然我这么说,但是很多同学还是会忘记f.close(), 对于这些同学,我们推荐傻瓜式操作方式:使用with关键字来帮我们管理上下文
    11 with open('a.txt', 'w') as f:     # w 只写模式,代码运行,文件存在直接清空,文件不存在,新建文件
    12     pass
    13 
    14 with open('a.txt', 'r') as read_f, open('b.txt', 'w') as write_f:   # 同时打开两个文件
    15     data = read_f.read()
    16     write_f.write(data)
    17 
    18 强调第一点:资源回收
    强调第一点:资源回收
    1 #强调第二点:
    2 f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-83 这就用到了字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。
    4 
    5 f=open('a.txt','r',encoding='utf-8')
    强调第二点:字符编码

    五、Python 2 中的 file 与 open

    1 #首先在python3中操作文件只有一种选择,那就是open()
    2 
    3 #而在python2中则有两种方式:file()与open()
    4 两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file
    file 与 open

    二、打开文件的模式

    文件句柄 = open('文件路径', '模式','字符编码')
    

    模式可以是以下方式以及他们之间的组合:

    字符 含义
    r 打开阅读,只读(默认)
    w 打开写入,首先截断文件
    a 打开写入,追加到文件末尾(如果存在)
    b 二进制模式
    t 文本模式,(默认)
    + 打开磁盘文件进行更新(读取和写入)
    U 通用换行符模式(向后兼容;不应在新代码中使用)
    #1. 打开文件的模式有(默认为文本模式):
    r,只读模式【默认模式,文件必须存在,不存在则抛出异常】
    w,只写模式【不可读;不存在则创建;存在则清空内容】
    a, 之追加写模式【不可读;不存在则创建;存在则只追加内容】
    
    #2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作
    # 而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、
    # 图片文件的jgp格式、视频文件的avi格式
    rb
    wb
    ab
    注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码
    
    #3. 了解部分
    "+" 表示可以同时读写某个文件
    r+, 读写【可读,可写】
    w+,写读【可读,可写】
    a+, 写读【可读,可写】
    
    
    x, 只写模式【不可读;不存在则创建,存在则报错】
    x+,写读【可读,可写】

    三、操作文件的方法

    #掌握
    f.read() #读取所有内容,光标移动到文件末尾
    f.readline() #读取一行内容,光标移动到第二行首部
    f.readlines() #读取每一行内容,存放于列表中
    
    f.write('1111
    222
    ') #针对文本模式的写,需要自己写换行符
    f.write('1111
    222
    '.encode('utf-8')) #针对b模式的写,需要自己写换行符
    f.writelines(['333
    ','444
    ']) #文件模式
    f.writelines([bytes('333
    ',encoding='utf-8'),'444
    '.encode('utf-8')]) #b模式
    
    #了解
    f.readable() #文件是否可读
    f.writable() #文件是否可写
    f.closed #文件是否关闭
    f.encoding #如果文件打开模式为b,则没有该属性
    f.flush() #立刻将文件内容从内存刷到硬盘
    

    四、bytes

    bytes 的方式写入内容可以跨平台,因为所有平台最终处理的都是 bytes 类型
     1 f = open("test.py", "rb", encoding="utf8")   # 报错
     2 
     3 # 你会觉得这样我们就已bytes的方式打开了一个文件,其实是错的, b 的模式不能指定编码
     4 
     5 
     6 f = open("test.py", "rb")
     7 # 这样的方式才是对的,b 的模式不用指定编码,因为b 就是原生二进制的方式
     8 
     9 
    10 data = f.read()
    11 print(data)
    12 
    13 # 这样就输出了test.py 中的内容,并且是bytes的模式
    14 
    15 
    16 # 如果我们想要看到编码后的内容怎么办呢?
    17 # 直接
    18 print(data.decode("utf8"))
    19 # 就可以了
    20 
    21 # 字符串  -->    encode  -->  bytes   编码过程
    22 # bytes  -->    decode  -->  字符串   解码过程
    rb 模式
     1 # 如果我们想要以 b的模式写入内容呢
     2 
     3 f = open("test1.py", "wb")   # 还是要注意:b 的方式拿文件句柄,不能指定编码
     4 f.write(bytes("1111
    ", encoding="utf8"))
     5 
     6 # 写入文件必须以 bytes 的方式,必须指定编码格式
     7 
     8 
     9 
    10 # 不用 bytes函数也可以指定编码格式写入内容
    11 
    12 f.write("艾伯特".encode("utf8"))
    13 
    14 # 这样就直接用字符串的encode方法,进行指定编码写入了内容
    Wb 模式
    1 f = open("test2.py", "ab")   # 注意:a 模式打开文件,光标会定位在最后
    2 f.write(bytes("1111
    ", encoding="utf8"))
    ab 模式

    五、文件句柄

    # f 就是一个文件句柄
    
    f.flush()
    
    # 将当前内存所写的东西全部刷新进硬盘,也就是保存文件
    

    我们打开文件之后,想要知道当前光标所在的位置怎么办呢?

    print(f.tell())
    
    # 显示光标坐在位置
    

    当我们知道光标所在的位置之后,发现我们并不喜欢那个位置怎么办呢?

    f.seek(3)
    
    # 指定光标所在的位置,3 代表字节位数
    

    当你想要将文件中的内容截取一段,截取以外的字符全部删除的时候,就要用 truncate 函数了

    f.truncate(4)
    
    # 截取字符,打开模式需要有写模式,4代表字节数
    

      

    当我们用 readlines 这个函数读文件的时候会发现,换行符是 ,其实这个结果是Python处理后的结果,那怎么知道他的庐山真面目呢?

    f = open("test3.py", "r", encoding="utf8", newline="")
    
    # 如果是 newline="" 代表读取真正的换行符号,每个平台的换行符不一样,例如:windows平台的就是 
    
    

    光标的注意事项

    一、read(3)

      1、文件打开方式为文本模式,代表读取3个   字符

      2、文件打开方式为b 模式,代表读取个3个   字节

    二、其余的文件内光标移动都是以字节为单位的,如:seek,tell,truncate

    注意:

      1、seek 有三种移动方式,0、1、2 其中1 和 2 必须在b 模式下进行,但是无论哪种模式,都是以 bytes 为单位移动的

      2、truncate 是截断文件,所以文件的打开方式必须为可写模式,但是不能用 w 或 w+ 等方式打开,因为那样直接清空文件了,所以在 r 、a 、a+模式下测试效果最好

    1 # seek要操作的文件,必须以 b 的模式去操作
    2 
    3 # seek 的参数
    4 
    5 # 0 代表从文件开头开始计算
    6 
    7 # 1 相对位置,从光标所在的位置开始计算
    8 
    9 # 2 相对位置,代表从文件末尾开始,参数是负数
    seek 0、1、2 详解

     六、高阶操作

     1 f = open("a.txt", "rb")
     2 
     3 for i in f:
     4     offs = -10
     5     while True:
     6         f.seek(offs,2)
     7         data = f.readlines()
     8         if len(data) > 1:
     9             print("文件的最后一行是%s" %(data[-1].decode("utf8")))
    10             break
    11         offs *= 2
    读取日志的最后一行

     七、文件处理 + 函数嵌套

    查询文件内容 + 修改文件内容

    测试的时候注意:查看文件内容和查询格式!!!

     1 fronrend albert.org
     2         bind 0.0.0.0:80
     3         option httplog
     4         option httpclose
     5         option forwardfor
     6         log global
     7         acl www hdr_reg(host) -i www.albertorg
     8         use_backend www.albert.org if www
     9 
    10 backend www.albert1.org
    11         server 101.10007.9 101.1007.9 weight 20 maxconn 30
    12         server 10.10.0.10 10.10.0.10 weight 9999 maxconn 33333333333
    13         server 10.10.10.1 10.10.10.1 weight 22 maxconn 2000
    14         server 2.2.2.4 2.2.2.4 weight 20 maxconn 3000
    15 
    16 backend www.albert2.org
    17         server 3.3.3.3 3.3.3.3 weight 20 maxconn 3000
    18 
    19 backend www.albert3.org
    20         server 10.10.0.10 10.10.0.10 weight 9999 maxconn 33333333333
    文件内容
    1 [{"backend":"www.albert1.org","record":{"server":"2.2.2.4","weight":20,"maxconn":3000}}, {"backend":"www.albert1.org","record":{"server":"2.2.2.5","weight":30,"maxconn":4000}}]
    2 
    3 
    4 
    5 #注意:粘贴完之后,请将上述代码,修改成一行
    查询格式
     1 def fetch(data):
     2     print("33[1;43m这是查询功能33[0m")
     3     print("33[1;43m用户查询的数据是:%s33[0m"%data)
     4     backend_data = "backend %s"%data
     5     with open("haproxy.txt", "r") as read_f:
     6         tag = False
     7         ret = []
     8         for read_line in read_f:
     9             if read_line.strip() == backend_data:
    10                 tag = True
    11                 continue
    12             if tag and read_line.startswith("backend"):
    13                     break
    14             if tag:
    15                 print("33[1;45m%s33[0m"%read_line, end="")
    16                 ret.append(read_line)
    17     return ret
    18 def add():
    19     pass
    20 
    21 def change():
    22     pass
    23 
    24 def delete():
    25     pass
    26 
    27 if __name__ == '__main__':
    28 
    29     msg = """
    30     1:查询
    31     2:添加
    32     3:修改
    33     4:删除
    34     5:退出
    35     """
    36     msg_dic = {
    37         "1":fetch,
    38         "2":add,
    39         "3":change,
    40         "4":delete
    41     }
    42     while True:
    43         print(msg)
    44         choice = input("请输入选项:").strip() # 清除用户输入字符串左右两边的空格、换行符、制表符
    45         if not choice:continue
    46         if choice == "5":break
    47         data = input("请输入你要查询的数据:")
    48         res = msg_dic[choice](data)
    49         print(res)
    查询功能
      1 import os
      2 def fetch(data):
      3     # print("33[1;43m这是查询功能33[0m")
      4     # print("33[1;43m用户查询的数据是:%s33[0m"%data)
      5     backend_data = "backend %s"%data
      6     with open("haproxy.txt", "r") as read_f:
      7         tag = False
      8         ret = []
      9         for read_line in read_f:
     10             if read_line.strip() == backend_data:
     11                 tag = True
     12                 continue
     13             if tag and read_line.startswith("backend"):
     14                     break
     15             if tag:
     16                 print("33[1;45m%s33[0m"%read_line, end="")
     17                 ret.append(read_line)
     18     return ret
     19 
     20 
     21 def add():
     22     pass
     23 
     24 
     25 
     26 def change(data):
     27     # print("这是修改功能")
     28     # print("用户输入的数据是",data)
     29     backend = data[0]["backend"] # 用户输入的地址  www.albert1.org
     30     backend_data = "backend %s"%backend
     31     #         server 2.2.2.4 2.2.2.4 weight 20 maxconn 3000
     32     old_server_record = "%sserver %s %s weight %s maxconn %s
    "%(" "*8, data[0]["record"]["server"],
     33                                           data[0]["record"]["server"],
     34                                           data[0]["record"]["weight"],
     35                                           data[0]["record"]["maxconn"])
     36     new_server_record = "%sserver %s %s weight %s maxconn %s
    " % (" " * 8, data[1]["record"]["server"],
     37                                                                  data[1]["record"]["server"],
     38                                                                  data[1]["record"]["weight"],
     39                                                                  data[1]["record"]["maxconn"])
     40     print("用户想要修改的内容",old_server_record)
     41     res = fetch(backend)
     42     print("来自change调用fetch-->查询的结果", res)
     43     if not res or old_server_record not in res:
     44         return "你要查询的内容不存在!"
     45     else:
     46         index = res.index(old_server_record)
     47         res[index] = new_server_record
     48     res.insert(0,"%s
    "%backend_data)
     49     with open("haproxy.txt", "r") as read_f,
     50             open("new_haproxy.txt", "w") as write_f:
     51         tag = False
     52         tag2 = False
     53         for read_line in read_f:
     54             if read_line.strip()== backend_data:
     55                 tag = True
     56                 continue
     57             if tag and read_line.startswith("backend"):
     58                 tag = False
     59             if not tag:
     60                 write_f.write(read_line)
     61             else:
     62                 if not tag2:
     63                     for i in res:
     64                         write_f.write(i)
     65                     tag2 = True
     66     os.rename("haproxy.txt", "haproxy.txt.bak")
     67     os.rename("new_haproxy.txt", "haproxy.txt")
     68     os.remove("haproxy.txt.bak")
     69 
     70 
     71 
     72 
     73 
     74 def delete():
     75     pass
     76 
     77 if __name__ == '__main__':
     78 
     79     msg = """
     80     1:查询
     81     2:添加
     82     3:修改
     83     4:删除
     84     5:退出
     85     """
     86     msg_dic = {
     87         "1":fetch,
     88         "2":add,
     89         "3":change,
     90         "4":delete
     91     }
     92     while True:
     93         print(msg)
     94         choice = input("请输入选项:").strip() # 清除用户输入字符串左右两边的空格、换行符、制表符
     95         if not choice:continue
     96         if choice == "5":break
     97         data = input("请输入你要查询的数据:")
     98         if choice != "1":
     99             data = eval(data)
    100         res = msg_dic[choice](data)
    101         print(res)
    查询 + 修改
      1 import os
      2 
      3 def file_handler(backend_data, res = None, type = "fetch"):    # 文件操作函数
      4     if type == "fetch":
      5         with open("haproxy.txt", "r") as read_f:
      6             tag = False
      7             ret = []
      8             for read_line in read_f:
      9                 if read_line.strip() == backend_data:
     10                     tag = True
     11                     continue
     12                 if tag and read_line.startswith("backend"):
     13                         break
     14                 if tag:
     15                     print("33[1;45m%s33[0m"%read_line, end="")
     16                     ret.append(read_line)
     17         return ret
     18     else:
     19         with open("haproxy.txt", "r") as read_f, 
     20                 open("new_haproxy.txt", "w") as write_f:
     21             tag = False
     22             tag2 = False
     23             for read_line in read_f:
     24                 if read_line.strip() == backend_data:
     25                     tag = True
     26                     continue
     27                 if tag and read_line.startswith("backend"):
     28                     tag = False
     29                 if not tag:
     30                     write_f.write(read_line)
     31                 else:
     32                     if not tag2:
     33                         for i in res:
     34                             write_f.write(i)
     35                         tag2 = True
     36         os.rename("haproxy.txt", "haproxy.txt.bak")
     37         os.rename("new_haproxy.txt", "haproxy.txt")
     38         os.remove("haproxy.txt.bak")
     39 
     40 def fetch(data):   # 查询函数
     41     # print("33[1;43m这是查询功能33[0m")
     42     # print("33[1;43m用户查询的数据是:%s33[0m"%data)
     43     backend_data = "backend %s"%data
     44 
     45     return file_handler(backend_data)
     46 
     47 def add():
     48     pass
     49 
     50 
     51 
     52 def change(data):  # 修改函数
     53     # print("这是修改功能")
     54     # print("用户输入的数据是",data)
     55     backend = data[0]["backend"] # 用户输入的地址  www.albert1.org
     56     backend_data = "backend %s"%backend
     57     #         server 2.2.2.4 2.2.2.4 weight 20 maxconn 3000
     58     old_server_record = "%sserver %s %s weight %s maxconn %s
    "%(" "*8, data[0]["record"]["server"],
     59                                           data[0]["record"]["server"],
     60                                           data[0]["record"]["weight"],
     61                                           data[0]["record"]["maxconn"])
     62     new_server_record = "%sserver %s %s weight %s maxconn %s
    " % (" " * 8, data[1]["record"]["server"],
     63                                                                  data[1]["record"]["server"],
     64                                                                  data[1]["record"]["weight"],
     65                                                                  data[1]["record"]["maxconn"])
     66     print("用户想要修改的内容",old_server_record)
     67     res = fetch(backend)
     68     print("来自change调用fetch-->查询的结果", res)
     69     if not res or old_server_record not in res:
     70         return "你要查询的内容不存在!"
     71     else:
     72         index = res.index(old_server_record)
     73         res[index] = new_server_record
     74     res.insert(0,"%s
    "%backend_data)
     75     file_handler(backend_data, res = res, type = "change")
     76 
     77 
     78 
     79 
     80 
     81 
     82 def delete():
     83     pass
     84 
     85 if __name__ == '__main__':
     86 
     87     msg = """
     88     1:查询
     89     2:添加
     90     3:修改
     91     4:删除
     92     5:退出
     93     """
     94     msg_dic = {
     95         "1":fetch,
     96         "2":add,
     97         "3":change,
     98         "4":delete
     99     }
    100     while True:
    101         print(msg)
    102         choice = input("请输入选项:").strip() # 清除用户输入字符串左右两边的空格、换行符、制表符
    103         if not choice:continue
    104         if choice == "5":break
    105         data = input("请输入你要查询的数据:")
    106         if choice != "1":
    107             data = eval(data)
    108         res = msg_dic[choice](data)
    109         print(res)
    解耦

    知识点:

    1、函数

    2、文件处理

    3、tag的用法

    4、程序的解耦

  • 相关阅读:
    java数组
    java 常用类
    java 集合(一)
    mysql相关操作(一)
    记录java BigDecimal
    hxg-yw
    一个困惑我好久的问题
    关于重载和重写的一些小知识
    几个常用的HTTP状态码
    死锁产生的原因和条件简述
  • 原文地址:https://www.cnblogs.com/albert0924/p/8723517.html
Copyright © 2020-2023  润新知