一、文件读写
• Python 内置了读写文件的函数,用法和 C 是兼容的。
• 操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(又称文件描述符),然后,通过操作系统提供的接口从这个文件对象操作;
文件读写的过程
1). 打开文件
2). 向文件中写入内容;
3). 关闭文件
1.打开文件, 以读的方式打开文件,返回一个文件对象;
#打开文件,以读的方式打开文件,返回一个文件对象;
# 如果文件不存在, open() 函数就会抛出一个 IOError 的错误,并且
给出错误码和详细的信息告诉你文件不存在;
f = open('/mnt/passwd')
print(f,type(f)
2.读取文件
#如果文件打开成功,接下来,调用 read() 方法可以一次读取文件的全部内容;
content = f.read()
print(content)
## 每次读取文件的一行内容
print(f.readline())
print(f.readline())
print(f.readline())
print(f.readline())
## 如果文件很小, read() 一次性读取最方便;
## 若文件过大:反复调用 read(size)比较保险
## 如果是配置文件,调用 readlines()
## 返回一个文件对象,类型为列表:
print(f.readlines())
## 批量去掉'\n'
print([line.strip() for line in f.readlines()])
3.关闭文件
#文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源。
f.close()
4.读写二进制文件
要读取二进制文件,比如图片、视频等等,用 ‘rb’ 模式打开文件即可
5.open函数的模式
r 以读的方式打开,定位到文件开头 , 默认的 mode
- 文件不存在, 则报错;
- 文件内容不会变化
- 文件只能读不能写入;
f = open('/mnt/pass','r')
print(f)
/mnt/pass 不存在,报错
r+ 以读写的方式打开,定位文件开头 , 可以写入内容到文件
w 以写的方式打开,打开文件的时候会清空文件的内容,并且不能读
- 文件不存在,则自动创建;
- 只能写不能读取文件;
- 文件内容会被覆盖掉;当文件以'w'的方式打开, 默认会清空文件内容;
f = open('/tmp/passwd','w')
print(f.writable()) 检验文件是否可写,可写,返回True;不可写,返回False
li = ['java', 'c', 'python', 'qq']
lis = [i+'\n' for i in li]
print(f.writelines(lis))
[kiosk@foundation10 tmp]$ cat passwd
java
c
python
qq
w+ 以读写的方式打开,定位到文件头,并且打开文件的时候也会清空文件的内容
f = open('/tmp/passwd','w+')
li = ['java', 'c', 'python']
lis = [i+'\n' for i in li]
f.writelines(lis)
[kiosk@foundation10 tmp]$ cat passwd
java
c
python
a 以写的方式打开,定位到文件的末尾,是一个追加的操作 , 但并不允许读
f = open('/tmp/passwd','a')
f.write('westos\n')
[kiosk@foundation10 tmp]$ cat passwd
java
c
python
westos
a+ 以读写的方式打开,定位到文件的末尾,追加的方式。若文件不存在,自动创建文件
在使用以上 mode 打开文件的时候,如果增加了b 模式,表示以二进制方式打开
• 二进制文件
要读取二进制文件,比如图片、视频等等,用 'rb' 模式打开文件即可
f = open('img01.jpg','rb')
res = f.read()
print(res)
f.close()
'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节
复制图片
5.文件指针移动
seek(offset,whence)
# offset: 偏移量; 2
# whence: 0:移动指针到文件最开始; 1: 不移动指针,2:移动到文件最后;
tell
# 查看当前指针的位置;
6.文件的其它操作
f.flush()函数,将缓冲区的内容写入到硬盘中
fileno() 函数,返回当前的文件描述符,一个数字
isatty() 函数,当前打开的文件是否是一个终端设备
closed 属性,当前文件是否关闭 ,|True,False, f.closed
file 对象是一个迭代器:
next() 方法 , 一行一行的读 , 每次读取一行
二、with语句与文件对象的遍历(文件是否可迭代)
python2.5以后加入了安全上下文管理器with语句;当执行完with语句之后会自动清理和关闭文件对象;
with open('/tmp/passwd') as f:
f = open('/tmp/passwd')
print(f.read()
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
判断文件对象是否可迭代
from collections import Iterable
with open('/tmp/passwd') as f:
f = open('/tmp/passwd')
print("文件对象是否迭代:",isinstance(f,Iterable))
for line in f:
print(line)
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
文件对象是否迭代: True
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
练习:
找出文件中出现最多的10个ip;
import random
import time
def create_ip_file(count,logfile):
# 生成所有的ip列表
ips = ['172.25.254.'+str(host) for host in range(1,255)]
# 写入文件;
with open(logfile,'w') as f: #w:默认清空文件内容
for i in range(count):
f.write(random.choice(ips)+'\n')
create_ip_file(1200,'ips.log')
print("日志文件生成成功") ##生成ips.log 文件
# 测试函数运行时间的装饰器timeit
def timeit(fun):
def wrapper(*args,**kwargs):
start = time.time()
res = fun(*args,**kwargs)
end = time.time()
print("%s runs %.3fs" %(fun.__name__,end-start))
return res
return wrapper
第一种方法:
@timeit
def sorted_by_ip(filename,count=10):
# 创建一个存储ip的字典
ips_dict = dict()
# 1. 读取文件内容
with open(filename) as f:
for ip in f:
ip = ip.strip() ## 去掉ip里面的空格;
if ip in ips_dict:
ips_dict[ip] += 1
else:
ips_dict[ip] = 1
return sorted(ips_dict.items(),key=lambda item:item[1],reverse=True)[:count]
print(sorted_by_ip('ips.log', count=10))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
日志文件生成成功
sorted_by_ip runs 0.001s
[('172.25.254.34', 12), ('172.25.254.224', 11), ('172.25.254.173', 11), ('172.25.254.15', 10), ('172.25.254.182', 10), ('172.25.254.137', 10), ('172.25.254.96', 10), ('172.25.254.135', 10), ('172.25.254.106', 9), ('172.25.254.7', 9)]
第二种方法:
倒入Counter 模块
from collections import Counter
@timeit
def new_sorted_by_ip(filename,count=10):
with open(filename) as f:
ipcount = Counter(f)
## 找出ip出现次数最多的前'count'位
return ipcount.most_common(count)
print(new_sorted_by_ip('ips.log',count=10))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
日志文件生成成功
new_sorted_by_ip runs 0.001s
[('172.25.254.34\n', 12), ('172.25.254.224\n', 11), ('172.25.254.173\n', 11), ('172.25.254.15\n', 10), ('172.25.254.182\n', 10), ('172.25.254.137\n', 10), ('172.25.254.96\n', 10), ('172.25.254.135\n', 10), ('172.25.254.106\n', 9), ('172.25.254.7\n', 9)]
Counter模块示例
from collections import Counter
li = ['a', 'a', 'c', 'd', 'rt', 'f']
word_count = Counter(li)
print(word_count.most_common(2))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
[('a', 2), ('c', 1)]
三.OS模块
1.查找目录内的所有内容
print(os.listdir('/var/log'))
['tallylog', 'lastlog', 'wtmp', 'samba', 'pluto', 'libvirt', 'audit', 'chrony', 'ppp', 'rhsm', 'glusterfs', 'speech-dispatcher', 'gdm', 'sa', 'tuned', 'yum.log', 'anaconda', 'secure-20180520', 'dmesg.old', 'Xorg.0.log.old', 'wpa_supplicant.log-20180601', 'spooler-20180603', 'wpa_supplicant.log-20180524', 'cron-20180529', 'boot.log', 'btmp-20180601', 'maillog-20180603', 'wpa_supplicant.log', 'spooler-20180529', 'dmesg', 'secure-20180513', 'btmp', 'maillog', 'Xorg.0.log', 'messages-20180529', 'cron-20180513', 'maillog-20180513', 'messages-20180520', 'messages-20180603', 'spooler-20180513', 'secure-20180529', 'cron-20180603', 'Xorg.1.log', 'spooler', 'wpa_supplicant.log-20180606', 'messages-20180513', 'spooler-20180520', 'messages', 'cron-20180520', 'maillog-20180520', 'maillog-20180529', 'secure-20180603', 'secure', 'httpd', 'wpa_supplicant.log-20180527', 'cron']
2. os.system执行shell命令, 直接打印命令的执行结果;返回值为命令的执行效果, 如果为0,代表执行成功, 反之, 不成功;
print(os.system('du -sh /etc/'))
print(os.system('las'))
31M /etc/
256
32512
3. os.popen执行shell命令;
res = os.popen('hostname')
hostname = res.read()
print("主机名为:",hostname)
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
主机名为: foundation20.ilt.example.com
4. 创建文件, 指定文件权限;
os.mknod('os.txt',0o644)
print("sucess")
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
sucess
[kiosk@foundation20 day_08]$ ll os.txt
-rw-r--r-- 1 kiosk kiosk 0 Jun 7 14:54 os.txt
5.删除文件
os.remove('os.txt')
6.创建 删除目录
os.mkdir('westos.dir')
[kiosk@foundation20 day_08]$ ls -ld westos.dir/
drwxrwxr-x 2 kiosk kiosk 6 Jun 7 14:57 westos.dir/
## 删除目录
os.removedirs('westos.dir')
7.在上层目录不存在情况下创建和删除目录或文件
os.makedirs('westos/qq/user')
[kiosk@foundation20 day_08]$ cd westos/qq/user/
[kiosk@foundation20 user]$
#删除目录
os.removedirs('westos/qq/user')
8.判断文件是否存在,及其类型
os.path.isfile('/etc/passwd') 判断是否是文件
os.path.isdir('/var') 是否为目录
os.path.ismount('/mnt') 是否被挂载
os.path.exists('/etc/passwd') 文件是否存在
os.path.isabs() 此路径是否是绝对路经
os.path.islink('/usr/bin/python3') 文件是否是链接文件
os.path.lexists() 测试路径是否存在
print(os.path.isfile('/etc/passwd'))
print(os.path.isdir('/var'))
print(os.path.ismount('/mnt'))
print(os.path.exists('/etc/passwd'))
print(os.path.islink('/usr/bin/python3'))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
True
True
False
True
True
9.Linux路径分隔符
## Windows: C:\book\etc
print(os.path.sep)
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
/
10.查询系统基本属性
all_info = os.uname()
print(all_info)
print(all_info.sysname)
print(all_info.machine)
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
posix.uname_result(sysname='Linux', nodename='foundation20.ilt.example.com', release='3.10.0-327.el7.x86_64', version='#1 SMP Thu Oct 29 17:29:29 EDT 2015', machine='x86_64')
Linux
x86_64
11.对目录和文件的操作
把目录名和文件名分割;
print(os.path.split('/var/log/messag'))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
('/var/log', 'messag')
拿出文件名
print(os.path.basename('/var/log/messag'))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
messag
拿出目录名
print(os.path.dirname('/var/log/messag'))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
/var/log
分离文件名和后缀名;
print(os.path.splitext('/etc/hello.txt'))
print(os.path.splitext('hello.py'))
print(os.path.splitext('hello.c'))
/usr/local/python3/bin/python3 /home/kiosk/PycharmProjects/day_08/02_6.6总结.py
('/etc/hello', '.txt')
('hello', '.py')
('hello', '.c')
重命名
os.rename('westos', 'westosdir')
[kiosk@foundation20 day_08]$ ls -ld westosdir/
drwxrwxr-x 2 kiosk kiosk 6 Jun 7 15:36 westosdir/
练习:修改指定的后缀名
#!/usr/bin/python3
import os
def rename_suffix(dirname, old_suffix, new_suffix):
# dirname: img
# old_suffix: .png
# new_suffix: .jpg
# if not dirname.endswith('/'):
# dirname = dirname + '/'
# 目录分隔符
sep = os.path.sep
if not dirname.endswith(sep): # img ----> img/
dirname = dirname + sep
# 如果后缀名不是.png, .jpg, 则加上'.'
if not old_suffix.startswith('.'): # png ---> .png
old_suffix = '.' + old_suffix
if not new_suffix.startswith('.'):
new_suffix = '.' + new_suffix
if os.path.exists(dirname):
# 1. 找出以.png结尾的所有文件;
suffix_lis = [filename for filename in os.listdir(dirname)
if filename.endswith(old_suffix)]
# 2. 分离文件名和后缀名, 拿出所有的文件名即可;
basename_lis = [os.path.splitext(file)[0] for file in suffix_lis]
# 3. 批量修改后缀名:(重命名)
# li = [os.rename(dirname+file+old_suffix, dirname+file+new_suffix) for file in basename_lis]
for file in basename_lis:
old_filename = dirname + file + old_suffix
new_filename = dirname + file + new_suffix
os.rename(old_filename, new_filename)
print("%s重命名为%s成功!" %(old_filename, new_filename))
# 这里的文件是相对路径
# os.rename('file1.png', 'file1.jpg')
else:
print("%s目录不存在" %(dirname))
import sys ## 导入命令行执行模块
# 代表传入了三个参数
if len(sys.argv) == 4:
dirname = sys.argv[1]
old_suffix = sys.argv[2]
new_suffix = sys.argv[3]
# rename_suffix('img', 'png', 'jpg')
rename_suffix(dirname, old_suffix, new_suffix)
else:
print("""
Usage: command dirname old_suffix new_suffix
""")
[root@foundation10 day01]# cp 01_后缀.py /bin/renameSuffix
[root@foundation10 day01]# chmod +x /bin/renameSuffix
[root@foundation10 mnt]# ls
ab.sh file1.png file2.png file3.png file4.png file5.png hllo.py passwd test1.jpg test2.jpg test3.jpg
[root@foundation10 mnt]# renameSuffix /mnt/ png jpg
/mnt/file1.png重命名为/mnt/file1.jpg成功!
/mnt/file2.png重命名为/mnt/file2.jpg成功!
/mnt/file3.png重命名为/mnt/file3.jpg成功!
/mnt/file4.png重命名为/mnt/file4.jpg成功!
/mnt/file5.png重命名为/mnt/file5.jpg成功!
[root@foundation10 mnt]# ls
ab.sh file1.jpg file2.jpg file3.jpg file4.jpg file5.jpg hllo.py passwd test1.jpg test2.jpg test3.jpg
#!/usr/bin/python3
import os
def rename_suffix(dirname, old_suffix, new_suffix):
# dirname: img
# old_suffix: .png
# new_suffix: .jpg
# if not dirname.endswith('/'):
# dirname = dirname + '/'
# 目录分隔符
sep = os.path.sep
if not dirname.endswith(sep): # img ----> img/
dirname = dirname + sep
# 如果后缀名不是.png, .jpg, 则加上'.'
if not old_suffix.startswith('.'): # png ---> .png
old_suffix = '.' + old_suffix
if not new_suffix.startswith('.'):
new_suffix = '.' + new_suffix
if os.path.exists(dirname):
# 1. 找出以.png结尾的所有文件;
suffix_lis = [filename for filename in os.listdir(dirname)
if filename.endswith(old_suffix)]
# 2. 分离文件名和后缀名, 拿出所有的文件名即可;
basename_lis = [os.path.splitext(file)[0] for file in suffix_lis]
# 3. 批量修改后缀名:(重命名)
# li = [os.rename(dirname+file+old_suffix, dirname+file+new_suffix) for file in basename_lis]
for file in basename_lis:
old_filename = dirname + file + old_suffix
new_filename = dirname + file + new_suffix
os.rename(old_filename, new_filename)
print("%s重命名为%s成功!" %(old_filename, new_filename))
#
# # 这里的文件是相对路径
# # os.rename('file1.png', 'file1.jpg')
#
else:
print("%s目录不存在" %(dirname))
rename_suffix('img', 'jpg', 'png')
/usr/local/python3/bin/python3.6 /home/kiosk/PycharmProjects/day01/01_后缀.py
img/fiile1.jpg重命名为img/fiile1.png成功!
img/fiile2.jpg重命名为img/fiile2.png成功!
img/fiile3.jpg重命名为img/fiile3.png成功!
img/fiile4.jpg重命名为img/fiile4.png成功!
img/fiile5.jpg重命名为img/fiile5.png成功!
[root@foundation10 day01]# cd img
[root@foundation10 img]# ls
fiile1.png fiile2.png fiile3.png fiile4.png fiile5.png test.sh
12.接收命令行传入的参数
import sys
# sys.argv返回一个列表, 一个值为脚本名称;
print(sys.argv)
# 脚本后跟的第一个参数: sys.argv[1]
# 脚本后跟的第2个参数: sys.argv[2]