Fork me on GitHub

Python开发【第三章】:文件操作

转载自:https://www.cnblogs.com/lianzhilei/p/5749932.html

一、文件操作模式概述

1、打开文件的模式:

  • r, 只读模式【默认】
  • w,只写模式【不可读;不存在则创建;存在则删除内容;】
  • a, 追加模式【不可读;不存在则创建;存在则只追加内容;】

2、"+" 同时读写某个文件:

  • r+,可读写文件。【可读;可写;可追加】
  • w+,写读
  • a+,追加读

3、"U"表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)

  • rU
  • r+U

4、"b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)

  • rb
  • wb
  • ab

二、文件操作常用功能

注:默认以下操作都是基于下面文件操作的:

我越无所适从
越会事与愿违
在交错的时空
灵魂加速下坠
Here we are, here we are, here we are
here we are

1、read()、readline()、readlines()的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
info_file = open("here_we_are",encoding="utf-8")    #默认读取模式
print(info_file)                                    #不加参数,直接打印
#<_io.TextIOWrapper name='here_we_are' mode='r' encoding='utf-8'>
 
print(info_file.read())                            #read参数,读取文件所有内容
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速下坠
#Here we are, here we are, here we are
 
print(info_file.readline())                        #readline,只读取文章中的一行内容
#我越无所适从
 
print(info_file.readlines())                        #readlines,把文章内容以换行符分割,并生成list格式,数据量大的话不建议使用
#['我越无所适从\n', '越会事与愿违\n', '在交错的时空\n', '灵魂加速下坠\n', 'Here we are, here we are, here we are\n']

 

2、seek、tell光标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#读取文件光标问题
info_file = open("here_we_are",encoding="utf-8")    #文件句柄
data = info_file.read()                                #默认光标在起始位置,.read()读取完后,光标停留到文件末尾
data2 = info_file.read()                               #data2读取到的内容为空
print(data)
print("--------",data2)
info_file.close()                                      #关闭文件
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速下坠
#Here we are, here we are, here we are
#--------
 
#用seek移动光标位置
info_file = open("here_we_are",encoding="utf-8")
print(info_file.tell())                         #tell 获取当前的光标位
print(info_file.readline().strip())
print(info_file.readline().strip())
print(info_file.readline().strip())
print(info_file.tell())
info_file.seek(0)                               #seek 移动光标到文件首部
print(info_file.readline().strip())             #从文件首部开始打印
info_file.close()                               #关闭文件
#0
#我越无所适从
#越会事与愿违
#在交错的时空
#60
#我越无所适从

 

3、文件循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#读取文件,并把第4行内容换成"-----我是分割线-------"
 
info_file = open("here_we_are",encoding="utf-8")
 
for index,line in enumerate(info_file.readlines()):        #先把文件内容以行为分割生成列表,数据量大不能用
    if index == 3:
        print("-----我是分割线-------")
        continue
    print(line.strip())
 
 
count = 0
for line in info_file:                       #建议使用方法,每读取一行,内存会把之前的空间清空,不会占用太多内存
    count +=1
    if count == 4:
        print("-----我是分割线-------")
        continue
    print(line.strip())
     
#我越无所适从
#越会事与愿违
#在交错的时空
#-----我是分割线-------
#Here we are, here we are, here we are 

 

4、flush 刷新

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#模拟安装进度条
import sys,time         #加载模块
 
for in range(40):
    sys.stdout.write("#")
    sys.stdout.flush()          #flush 强制刷新缓存到内存的数据写入硬盘
    time.sleep(0.1

 

5、truncate 截断

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
info_file = open("here_we_are","a")       #非r、w模式
info_file.seek(10)
info_file.truncate(40)
###########文件内容###########
#我越无所适从
#越会事与愿违

注:truncate跟光标位置无关,从文件首部开始截取字符;如果是truncate(0)会把文件清空

 

6、with 语句

为了避免打开文件后忘记关闭,可以通过管理上下文,即:

1
2
3
with open('log','r') as f:
      
    ...

如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源。

在Python 2.7 后,with又支持同时对多个文件的上下文进行管理,即:

1
2
with open('log1') as obj1, open('log2') as obj2:
    pass  

 

7、r+ 读写  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#读写模式
info_file = open("here_we_are","r+",encoding="utf-8")       #读写模式
print(info_file.readline().strip())
print(info_file.readline().strip())
print(info_file.tell())                             #查看读取两行后光标的位置
info_file.write("\nfffffffff")                    #没有写入数据到光标的位置,而是以追加的模式写到了文件最后
print(info_file.tell())                             #查看写入数据后光标的位置
print("----------\n",info_file.read())            #从上次读取的光标的位置开始读取到最后 注:新加入的内容不会打印
info_file.close()
###########打印输出###########
#我越无所适从                                        #注: 读写模式下文件以追加的方式进行写入
#越会事与愿违
#40
#130
#----------
#在交错的时空
#灵魂加速下坠
#Here we are, here we are, here we are
###########文件内容###########
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速下坠
#Here we are, here we are, here we are
#fffffffff

由上面的实例可知,读写模式下写入是追加写的,没有添加到指定行,而是写到文件的末尾。   r+模式下真的只是读和追加写吗?!看看下面的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#r+模式下对文件进行修改,文件修改在博客下面进行描述
with open("here_we_are","r+",encoding="utf-8") as info_file:    
    file_read = info_file.read()
    info_file.seek(0)                                                #seek 光标移到文件首部
    new_file = file_read.replace("灵魂加速下坠","灵魂加速shangsheng")     #把文件进行修改
    info_file.write(new_file)                                        #写入到文件中
 
############执行完后文件内容############
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速shangsheng
#Here we are, here we are, here we are

看完上面代码你可能会想,擦,what are you 弄啥嘞?第一个程序不是说光标跟文件的写入文件没关系吗?不应该会把修改的内容添加到文件末尾吗?怎么替换了?(黑人问号脸),来看看下面的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#r+模式下对文件进行修改,文件修改在博客下面进行详细描述
with open("here_we_are","r+",encoding="utf-8") as info_file:    
    file_read = info_file.read()
    info_file.seek(0)                                                #seek 光标移到文件首部
    print(info_file.readline())                                      #新增一行文件打印,光标到第一行未
    new_file = file_read.replace("灵魂加速下坠","灵魂加速shangsheng")     #把文件进行修改
    info_file.write(new_file)                                        #写入到文件中
 
############执行完后文件内容############
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速下坠
#Here we are, here we are, here we are我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速shangsheng
#Here we are, here we are, here we are

这次在seek光标位置和对文件修改之间加了一条print,此刻会发现虽然光标在第一行尾末,但是新添加的内容写到了文件末尾,用的是追加模式。下面我们可以坐下总结了

总结:r+模式下,如果在.write()进行写入内容前,有print()输出,则要写的内容会从文件尾部开始写入,使用的是读、追加模式;如果在.write()进行写入内容前,是seek()移动光标,则要写的内容会从移动到的光标开始进行写入,会把原来的内容覆盖掉,而不是整体后移,这点要记住;如果在.write()进行写入内容前,既没有print()也没有seek()光标移动,这种情况之前想的的情况,就是r+读写模式能先写后读吗?r+模式下默认光标在文件的首部,此时会直接从文件开头进行写入,效果等同于seek(0)。关于最后一点,参考a+模式。

 

8、 w+ 写读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#写读模式
info_file = open("here_we_are2","w+",encoding="utf-8")      #写读模式 此模式一般不用
 
info_file.write("我越无所适从\n")                              #向文件中写入四行内容
info_file.write("越会事与愿违\n")
info_file.write("在交错的时空\n")
info_file.write("灵魂加速下坠\n")
print(info_file.tell())                                         #打印光标  此时光标在写入文件末尾
info_file.seek(0)                                               #光标回到文件首部 如果不seek的话会从文件末尾打印,即为空
print(info_file.tell())
print(info_file.readline())                                     #打印第一行,光标回到第一行末尾
info_file.write("------这一行应该写到第二行------")           #理论上应该写在第一行的末尾后面
info_file.close()
###########打印输出###########
#80
#0
#我越无所适从
###########文件内容###########
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速下坠
#------这一行应该写到第二行------

总结:读写模式一定要先写后读吗?能不能先读后写?  如果先读的话,由于用的是w+模式打开的文件,打开后会清空原文件内容,所有读取的到东西是空的。另W+模式后期用的很少,了解即可,包括a+追加读这种模式;另w+模式下,光标会跟随文件写入移到到文件末尾,不用seek移到光标的话,打印内容为空

注:w+模式下,关于.write()跟seek()和print()的关系与r+模式下是一样一样的。w+打开文件后先清空,然后追加写,如果.write()前有seek()的话会从光标位置覆盖写。

 

9、a+ 追加读

虽然a+不重要,但还是要通过下面的例子做下简单了解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#a+ 追加写
with open("here_we_are","a+",encoding="utf-8") as info_file:    #追加写
    print(info_file.tell())                                         #打印光标 默认在文件尾部
    info_file.seek(0)                                               #seek 光标移到文件首部
    info_file.write("----我是第一行------")                       #判断.write()与seek的关系
###########打印输出###########
#117
###########执行后文件内容###########
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速下坠
#Here we are, here we are, here we are----我是第一行------

总结:通过上面的程序可以得出,a+模式下光标位置为文件末尾,如果要print()的话要结合seek()进行使用;另外与r+、w+不同的是,.write()与seek()没有关系,只能写内容到文件末尾,一直都是追加模式!  

 

10、rb 二进制读

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#二进制读取
info_file = open("here_we_are","rb")          #二进制模式读取
                                              #应用场景:网络传输         
print(info_file.readline())
print(info_file.readline())
print(info_file.readline())
#b'\xe6\x88\x91\xe8\xb6\x8a\xe6\x97\xa0\xe6\x89\x80\xe9\x80\x82\xe4\xbb\x8e\r\n'
#b'\xe8\xb6\x8a\xe4\xbc\x9a\xe4\xba\x8b\xe4\xb8\x8e\xe6\x84\xbf\xe8\xbf\x9d\r\n'
#b'\xe5\x9c\xa8\xe4\xba\xa4\xe9\x94\x99\xe7\x9a\x84\xe6\x97\xb6\xe7\xa9\xba\r\n'

 

11、wb 二进制写(ab也一样)

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#二进制写入
info_file = open("here_we_are2","wb")          #二进制模式写入
                            #应用场景与rb相似
info_file.write("我越无所适从\n".encode())    #对写入的字符串进行编码
info_file.write("越会事与愿违\n".encode())
info_file.close()

 

 12、文件的修改

文件修改方式:

  • 把文件读取到内存当中,对内存进行修改,把修改后的内容写入到原文件(旧内容被清空)
  • 如果在硬盘上直接写,会进行覆盖,硬盘上不能进行插入,原来的内容不会整体后移,而是直接覆盖掉
  • 把文件读取到内存当中,对内存进行修改,把修改的内容另存为新的文件(旧文件保留)

 ① 另存方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
info_file = open("here_we_are","r",encoding="utf-8")
new_file = open("here_we_are2","w",encoding="utf-8")
 
for line in info_file:
    if "灵魂加速下坠" in line:
        line = line.replace("灵魂加速下坠","灵魂加速shangsheng")
    new_file.write(line)
     
##########执行后文件here_we_are2内容#########
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速shangsheng
#Here we are, here we are, here we are

② r+模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#r+模式下对文件进行修改,
with open("here_we_are","r+",encoding="utf-8") as info_file:
    file_read = info_file.read()                               #加载内容到内存,此时光标在文件末尾
    new_file = file_read.replace("灵魂加速下坠","灵魂加速shangsheng")     #把文件进行修改
    info_file.truncate(0)                                      #清空原文件,不会影响光标位置
    info_file.seek(0)                                #移动光标到文件首部,不做操作的话,新的内容会添加到之前光标的位置
    info_file.write(new_file)                                        #修改的内容写入到文件中
 
############执行完后文件内容############
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速shangsheng
#Here we are, here we are, here we are

③ a+模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#a+模式下对文件进行修改,
with open("here_we_are","a+",encoding="utf-8") as info_file:
    info_file.seek(0)                                   #默认光标在文件末尾
    file_read = info_file.read()                               #加载内容到内存,此时光标在文件末尾
    new_file = file_read.replace("灵魂加速下坠","灵魂加速shangsheng")     #把文件进行修改
    info_file.truncate(0)                                      #清空原文件,不会影响光标位置
    info_file.seek(0)                                #移动光标到文件首部,不做操作的话,新的内容会添加到之前光标的位置
    info_file.write(new_file)                                        #修改的内容写入到文件中
     
############执行完后文件内容############
#我越无所适从
#越会事与愿违
#在交错的时空
#灵魂加速shangsheng
#Here we are, here we are, here we are

 

三、练习

1、对文件实现替换功能 

操作文件

Somehow, it seems the love I knew was always the most destructive kind
不知为何,我经历的爱情总是最具毁灭性的的那种
Yesterday when I was young
昨日当我年少轻狂
The taste of life was sweet
生命的滋味是甜的
As rain upon my tongue
就如舌尖上的雨露
I teased at life as if it were a foolish game
我戏弄生命 视其为愚蠢的游戏
The way the evening breeze
就如夜晚的微风
May tease the candle flame
逗弄蜡烛的火苗
The thousand dreams I dreamed
我曾千万次梦见
The splendid things I planned
那些我计划的绚丽蓝图
I always built to last on weak and shifting sand
但我总是将之建筑在易逝的流沙上
I lived by night and shunned the naked light of day
我夜夜笙歌 逃避白昼赤裸的阳光
And only now I see how the time ran away
事到如今我才看清岁月是如何匆匆流逝
yesterday

流程图

 

程序code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
 
##实现简单的替换功能
with open("yesterday","r+",encoding="utf-8") as info_file:      #with 方式打开文件yesterday
    old_data = input("Please input to modify content:")
    if old_data in info_file.read() and old_data != "":            #判断输入的字符是否存在或不为空
            new_data = input("Please input to the content of the modified:")
            info_file.seek(0)                                       #光标回到文件首部
            new_file = info_file.read().replace(old_data,new_data)  #文件内容替换
            info_file.seek(0)
            info_file.truncate(0)                                   #清空原文件
            info_file.write(new_file)                               #写入修改的内容到文件
    else:
        print("The content of the input does not exist")

 

2、修改haproxy配置文件

  • 可查询
  • 可增加
  • 可删除
  • 具体实现参考readme

需知readme:

# 实现简单的替换功能

### 作者介绍:
* author:lzl
### 博客地址:
* http://www.cnblogs.com/lianzhilei/p/5722771.html(第八 集合)
* http://www.cnblogs.com/lianzhilei/p/5749932.html
* http://www.cnblogs.com/lianzhilei/p/5754069.html
* http://www.cnblogs.com/lianzhilei/p/5754810.html

### 实现效果:
* 查看yesterday文件,输入想要替换的字符,然后输入新替换的字符,然后查看文件旧的字符被新的字符所替换

### 运行环境:
* Python3.0+


### 目录结构:

    Day3
    ├── 文件替换
    │   ├── file_relpace.py
    │   └── yesterday
    │   ├── file_relpace.png
    │   └── readme.txt

### linux 运行说明:

* 上述文件都拷贝到同一级目录下
* 加执行权限 chmod 755  file_relpace.py
* 执行程序   python  file_relpace.py
readme

操作文件:

global       
        log 127.0.0.1 local2
        daemon
        maxconn 256
        log 127.0.0.1 local2 info
defaults
        log global
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
        option  dontlognull

listen stats :8888
        stats enable
        stats uri       /admin
        stats auth      admin:1234

frontend oldboy.org
        bind 0.0.0.0:80
        option httplog
        option httpclose
        option  forwardfor
        log global
        acl www hdr_reg(host) -i www.oldboy.org
        use_backend www.oldboy.org if www

backend www.oldboy.org
        server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000
haproxy

流程图:

 

程序code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
 
def if_continue():                      #定义函数if_continue() 提示用户是否继续操作
    if_cont = input("\n\33[34;1mDo you want to continue to operate on files【y】/【n】:\33[0m\n")
    if if_cont == "y":
        pass
    else:
        exit()
 
def info_message(options):              #定义函数info_message() 提示用户操作信息
    print("\33[31;1mInfo of %s\33[0m".center(50,"-")%options)
 
with open("haproxy","a+",encoding="utf-8") as file_haproxy:       #a+模式打开haproxy文件
    while True:                                                    #设置while循环
        dict_file = {}
        file_haproxy.seek(0)                                        #移动光标到文件首部
        for line in file_haproxy:
            if "backend" in line and "use_backend" not in line: #提前文件中backend信息并生成字典dict_file
                dict_file[line.split()[1]]=file_haproxy.readline().strip()
 
        print("File_Operations_Backend".center(50,"*"),"\n1\tQuery\n2\tAdd\n3\tDel\nq\tQuit")
        user_choice = input("\33[34;1mSelect the ID to operate:\33[0m")  #让用户选择操作文件的模式
 
        if user_choice == "1":
            info_query = input("\33[34;1mInput information to query:\33[0m")
            if info_query in dict_file.keys():     #判断输入的查询的信息是否存在
                info_message("Query")
                print(dict_file[info_query])        #如果查询的backend存在 打印查询的信息
            else:                                  #否则提示没有查询到相关信息
                print("\33[31;1mError:No query to the corresponding information!\33[0m")
            if_continue()
 
        elif user_choice == "2":
            info_add = input("\33[34;1mInput information to add:\33[0m")
            try:                                    #判断输入的类型是否可以转换成字典格式
                dict_add = eval(info_add)           #字符串转换成字典
                if dict_add["backend"not in dict_file.keys():     #判断新增的信息没有存在于文件中
                    dict_add_record = dict_add["record"]             #把要添加的信息定义到变量file_add 中
                    file_add = "backend %s\n\t\tserver %s weight %s maxconn %s\n"%(dict_add["backend"],
                                dict_add_record["server"],dict_add_record["weight"],dict_add_record["maxconn"],)
                    file_haproxy.write(file_add)           #把新增的信息写到文件中
                    info_message("Add")                     #打印增加成功
                    print("\33[32;1mSuccessfully adding information backend %s to a file\33[0m"%(dict_add["backend"]))
                else:                                       #如果已经存在 打印信息已经存在
                    print("\33[31;1mError:Add the information already exists!\33[0m")
                if_continue()
            except Exception:                           #如果输入的字符不能转换为字典格式 提示错误
                    print("\33[31;1mError:Please enter the dict format!\33[0m")
                    if_continue()
 
        elif user_choice == "3":
            info_del = input("\33[34;1mInput information to del:\33[0m")
            try:                                         #判断输入的类型是否可以转换成字典格式
                dict_del = eval(info_del)                    #字符串转换成字典
                if dict_del["backend"in dict_file.keys():       #判断要删除的信息有没有存在于文件中
                    file_haproxy.seek(0)
                    list_del = file_haproxy.readlines()         #把文件信息写入列表list_del
                    index = list_del.index("backend %s\n"%(dict_del["backend"]))  #获取要删除信息的下标
                    del list_del[index]                         #在列表中删除输入信息
                    del list_del[index]
                    file_haproxy.seek(0)
                    file_haproxy.truncate(0)                    #文件清空
                    for line in list_del:                       #把list_del内容写入到文件中
                        file_haproxy.write(line)
                    info_message("Del")                         #提示删除成功
                    print("\33[32;1mSuccessfully delect information backend %s to a file\33[0m" % (dict_del["backend"]))
 
                else:                                           #如果要删除的信息不再文件中,打印信息不存在
                    print("\33[31;1mError:Delect the information is not exists!\33[0m")
                if_continue()
            except Exception:                               #如果输入的字符不能转换为字典格式 提示错误
                print("\33[31;1mError:Please enter the dict format!\33[0m")
                if_continue()
 
        elif user_choice == "q":
            print("\33[31;1mExit\33[0m".center(30,"-"))
            exit()
 
        else:
            print("\33[31;1mError:Select the ID does not exist!\33[0m")
posted @ 2018-09-20 11:41  replaceroot  阅读(89)  评论(0)    收藏  举报