python文件管理
一.文件处理流程
- 1,打开文件,得到文件句柄并赋值给一个变量
- 2,通过句柄对文件进行操作
- 3,关闭文件
二.基本操作
- 打开模式
文件句柄 = open(‘文件路径’, ‘模式’, 指定编码)
打开文件的模式有:
r ,只读模式【默认模式,文件必须存在,不存在则报错】
w,只写模式【不可读;不存在则创建;存在则清空内容】
x, 只写模式【不可读;不存在则创建,存在则报错】
a, 追加模式【可读;不存在则创建;存在则只追加内容】
“+” 表示可以同时读写某个文件
r+, 读写【可读,可写】
w+,写读【可读,可写】
x+ ,写读【可读,可写】
a+, 写读【可读,可写】
“b”表示以字节的方式操作
rb 或 r+b
wb 或 w+b
xb 或 w+b
ab 或 a+b
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码 - 操作
(1)读
f.read() #按字符读文件
f.readline() #按行读文件
f.readlines() #按行读所有文件内容
(2)写
f.write() #在当前光标后开始写文件
(3)刷到硬盘
f.flush() #立即刷到硬盘
(4)关闭文件
f.close() #关闭文件
(5)光标移动
f.read() #按字符读取问价,光标按字符移动
f.seek() #按字节读取文件,光标按字节移动;
f.seek( ,whence) #whence默认为0,代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
f.truncate() #默认从当前光标位置截断,后面内容删除,可传入参数,指该字节处截断
f.tell() #获取文件当前位置
(6)上下文管理
with open(‘文件路径’, ‘模式’) as f: #执行完操作后自动删除f
pass
(7)扩展
复制图片(视频)文件:
read_file = open(‘a.jpg’,’rb’)
write_file = open(‘a.copy.jpg’ , ‘wb’)
write_file.write(read_file.read())
read_file.close()
write_file.close()
文件修改:
import os
os.remove(‘a.txt’) #删除a.txt文件
os.rename(‘.a.txt.swp’, ‘a.txt’) #重命名.a.txt.swp文件为a.txt
linux中文件句柄泄露
1.文件句柄泄露
在linux中,如果一个文件正在被某个进程占用,用户操作rm删除该文件后,我们ls后发现文件已经不存在了,但实际上该文件仍然在磁盘上。直到使用它的进程退出后,文件占用的磁盘空间才会被释放。
其原理如下:
- 在linux中,每个文件都有2个计数器,i_count和i_nlink。i_count表示文件正在被调用的数量。i_nlink表示硬链接的数量。可以理解为i_count为内存的引用计数器,i_nlink为磁盘的引用计数器。当一个文件被某一个进程引用时,对应i_count数就会增加;当创建文件的硬链接的时候,对应i_nlink数就会增加。
- rm操作是将文件的i_nlink减少了,如果没有其它的硬链接i_nlink就为0了;但由于该文件依然被进程引用,因此,此时文件对应的i_count并不为0,所以即使执行rm操作,但系统并没有真正删除这个文件,当只有i_nlink及i_count都为0的时候,这个文件才会真正被删除。也就是说,还需要解除该进程的对该文件的调用才行。
备注,在这种情况下,就需要使用lsof工具来查看文件被进程的占用情况了。
解决进程文件句柄泄露导致磁盘空间无法释放问题
问题的产生
- 突然接到一台服务器磁盘空间使用率达到90%的报警,于是登陆机器查看磁盘使用情况,发现确实外挂到/data的一块磁盘使用率达到了90%:
[root@awsuw7-46 data]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/xvda2 100G 17G 84G 17% /
devtmpfs 30G 0 30G 0% /dev
tmpfs 29G 0 29G 0% /dev/shm
tmpfs 29G 2.7G 27G 10% /run
tmpfs 29G 0 29G 0% /sys/fs/cgroup
/dev/xvdf 246G 209G 26G 90% /data
tmpfs 5.8G 0 5.8G 0% /run/user/1000
tmpfs 5.8G 0 5.8G 0% /run/user/1003
分析问题
- 对于这种情况我一般的处理方法是跳到对应的目录,查看哪个目录占用的空间比较大,然后进一步清理。由于这块磁盘是外挂到/data目录,因此查看下该目录下各个目录磁盘的占用情况:
[root@awsuw7-46 data]# du -h --max-depth=1
3.7G ./photo
16K ./lost+found
9.1G ./mls2
36K ./parser
79G ./web
15G ./mls
106G
- 可以发现一个奇怪的现象:该外挂目录总共才使用了106G,但是df -h显示的是该磁盘已经使用了209G,那么使用的另外那103G去哪儿了呢,况且这块磁盘也没有多个分区,就这一个分区且挂载到了/data下。这确实是个很奇怪的问题,于是网上搜索了下原因,原来是不正确的删除文件导致的:
- 在Linux操作系统中,当一个文件被删除后,在文件系统目录中已经不可见了,所以du就不会再统计它了。然而如果此时还有运行的进程持有这个已经被删除了的文件的句柄,那么这个文件就不会真正在磁盘中被删除, 分区超级块中的信息也就不会更改,所以df命令查看的磁盘占用没有减少。我们知道在Linux中磁盘分区的超级块是非常重要的,在superblock中记录该分区上文件系统的整体信息,包括inode和block的总量,剩余量,使用量,以及文件系统的格式等信息。因此,superblock不更新,那么磁盘的使用量必然不会变化,操作系统对于文件的存盘都是需要事先读取superblock的信息,然后分配可用的inode和block。
解决问题
- 1.首先找出文件句柄泄露的进程,我的方法比较low,找出系统中启动时间比较久的java进程(因为这台机器主要是java服务),然后用lsof看这个进程的文件句柄使用情况。之所以这么做主要是因为最近启动的进程发生句柄泄露的可能性很小,因为即使存在句柄泄露,重启后也会释放文件句柄的。可以看出2962这个进程最可能发生句柄泄露了。
[root@awsuw7-46 data]# ps -eo pid,lstart,comm | grep java
746 Thu Jan 18 19:44:15 2018 java
1117 Thu Feb 8 02:20:03 2018 java
1160 Thu Feb 8 02:20:09 2018 java
2962 Thu Nov 16 23:08:40 2017 java
3610 Wed Feb 7 22:55:37 2018 java
4579 Thu Feb 8 20:45:09 2018 java
5155 Mon Dec 25 19:01:32 2017 java
6481 Wed Jan 10 05:16:28 2018 java
6519 Thu Jan 18 00:51:07 2018 java
9756 Thu Feb 8 02:36:23 2018 java
- 2.使用lsof分析上面找到的进程文件句柄使用情况,可以看出该进程确实存在句柄泄露,而且非常严重,已经有2208个文件没有释放了:
[root@awsuw7-46 ~]# lsof -p 2962 | grep "delete" | wc -l
2208
[root@awsuw7-46 ~]# lsof -p 2962 | grep "delete" | head -n 20
java 2962 web 17r REG 202,2 2098273 17844538 /tmp/winstone962950350375526798.jar (deleted)
java 2962 web 168w REG 202,80 0 1969499 /data/web/mls/data/jobs/mls_91/builds/590/23.log (deleted)
java 2962 web 325w REG 202,80 0 6455947 /data/web/mls/data/jobs/mls_39/builds/1080/10.log (deleted)
java 2962 web 341w REG 202,80 0 1975873 /data/web/mls/data/jobs/mls_113/builds/1054/29.log (deleted)
java 2962 web 347w REG 202,80 0 2506849 /data/web/mls/data/jobs/mls_59/builds/.1073/21.log (deleted)
java 2962 web 350w REG 202,80 8192 1975877 /data/web/mls/data/jobs/mls_113/builds/1054/31.log (deleted)
java 2962 web 352w REG 202,80 0 5387403 /data/web/mls/data/jobs/mls_80/builds/505/23.log (deleted)
java 2962 web 354w REG 202,80 0 3422611 /data/web/mls/data/jobs/mls_29/builds/.385/23.log (deleted)
- 3.重启上面找到的发生内存泄露的进程,发现磁盘使用量回归正常状态:
[ec2-user@awsuw7-46 ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/xvda2 100G 17G 84G 17% /
devtmpfs 30G 0 30G 0% /dev
tmpfs 29G 0 29G 0% /dev/shm
tmpfs 29G 2.7G 27G 10% /run
tmpfs 29G 0 29G 0% /sys/fs/cgroup
/dev/xvdf 246G 128G 106G 55% /data
tmpfs 5.8G 0 5.8G 0% /run/user/1000
tmpfs 5.8G 0 5.8G 0% /run/user/1003
tmpfs 5.8G 0 5.8G 0% /run/user/1005
tmpfs 5.8G 0 5.8G 0% /run/user/1008
tmpfs 5.8G 0 5.8G 0% /run/user/1007
tmpfs 5.8G 0 5.8G 0% /run/user/1006