💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
Python 基础之模块与文件操作
技能目标
- 掌握模块和包的使用方式
- 掌握常用模块
- 掌握文件和目录操作
本章介绍 Python 的模块与包的使用方式、文件与目录操作等高级技术。
4.1 模块与包
如果编写的程序中类和函数较多时,就需要对它们进行有效的组织分类,在 Python 中
模块和包都是组织的方式。复杂度较低可以使用模块管理,复杂度高则还要使用包进行管理。
4.1.1 模块
模块是 Python 中一个重要的概念,实际上就是包含 Python 函数或者类的程序。模块
就是一个包含 Python 定义和语句的文件,把一组相关的函数或代码组织到一个文件中,一
个文件即是一个模块。模块的文件名=模块名+后缀.py。模块之间代码共享,可以相互调用,
实现代码重用,并且模块中函数名称必须唯一。
1.模块定义
下面代码演示模块的定义,保存的文件名是 myModule.py。
#fileName : myModule.py
def add(a,b):
print (a+b)
def mul(a,b):
print (a*b)
在模块 myModule 中,定义了 2 个函数,一个加法函数和一个乘法函数。它们处理的
问题是同类的,作为一个模块定义。
2.模块导入
使用模块中的函数时,要先导入模块才能使用,导入有 2 种方式。
在一行导入一个模块,语法如下。
语法:
import 模块名
还可以在一行导入多个模块,语法如下。
语法:
import 模块名 1[,模块名 2][,模块名 3]…
模块和变量一样也有作用域的区别。如果在模块的顶层导入,则作用域是全局的。如
果在函数中导入,则作用域是局部的,其作用域只是所在的函数中。一个模块只能被加载一
次,无论它被导入多少次,可以阻止多重导入时代码被多次执行。在实际编码时,推荐直接
在顶层导入。
导入的模块也分几种,有 Python 的标准库模块、第三方模块和应用程序自定义的模块。
加载执行时在搜索路径中找到指定的模块,如果是第一次导入,模块将被加载并执行,之后
再调用时就不需要再次加载了。
示例 1:导入标准库模块 sys。
示例代码如下:
import sys
print (sys.platform)
#结果
linux
Python 的标准库模块 sys 包含了 Python 环境相关的函数,sys.platform 返回当前平台
的系统名称。
示例 2:导入并调用自定义模块 myModule
示例代码如下:
import myModule
myModule.add(2,3)
myModule.mul(2,3)
print (myModule.__name__)
#结果
5
6
myModule
模块名就是定义的文件名。在调用模块中函数的语句格式是“模块名.函数名”。每个模块
都有__name__属性,表示模块的名称。
如果不使用模块名,而直接用函数名进行调用,就需要在导入时指定需要使用模块的属
性,一行导入一个模块属性的语法如下。
语法:
from 模块名 import 属性名
一行导入模块的多个属性语法如下。
语法:
from 模块名 import 属性名 1[,属性名 2] [,属性名 3]…
示例 3:导入模块属性
代码如下所示:
from myModule import add,mul
add(2,3)
mul(2,3)
#结果
5
6
示例 3 的代码是先导入模块 myModule 的 add()、mul()函数,然后,可以不使用模块名,
直接使用函数名调用。
另外,还可以使用 as 关键字为模块或模块属性重新命名,语法如下。
语法:
import 模块名 as 模块新名称
from 模块名 import 属性名 as 属性新名称
示例 4:使用 as 关键字为模块重新命名
示例代码如下:
from myModule import add as add1,mul as mul1
add1(2,3)
mul1(2,3)
#结果
5
6
示例 4 的代码中,先将函数 add()重命名为 add1,mul 重命名为 mul1。随后,程序中
可以用新的名称调用函数。
4.1.2 包
当程序中的模块非常多时,可以把模块再进行划分,组织成包。包实际上就是一个目
录,但必须包含一个“__init__.py”文件。“__init__.py”可以是一个空文件,表示当前目录是一
个包。包还可以嵌套使用,包中可以包含其它子包。
1.包的使用
导入包中的模块只需要在模块名前加上包的名称即可,如按以下方式组织的目录:
project/
#目录
project.py
subproject/
#子目录
__init__.py
submodel.py
示例 5:在 project.py 中调用包 subproject 中 submodel.py 模块
示例代码如下:
#submodel.py
def add(a,b):
return a+b
#project.py
import subproject.submodel
print (subproject.submodel.add(1,3))
[root@localhost project]# python3 project.py
4
示例 5 中,先导入加入包名 subproject.submodel,再调用执行包 subproject.submodel
中的函数 add()。
2.__init__.py
前面使用的是空__init__.py 文件,也可以在里添加代码,它的作用实际上是初始化包
中的公共变量。在第一次使用 import 导入 subproject 包中的任何部分后,会执行包中的
__init__.py 文件代码。
示例 6:在 subproject 目录中的__init__.py,加入如下代码:
name = '__init__.py'
print ('subproject->',name)
[root@localhost project]# python3 project.py
subproject-> __init__.py
4
在命令行,输入“subproject-> __init__.py”可以看到__init__.py 的执行结果。
4.2 常用模块
Python 中已经提供有很多模块,同时用户也可以自定义模块。本章将讲解一些常用的
模块,如表 4-1 所示。
表 4-1 Python 常用模块列表
模块名称
说明
copy
复制
keyword
记录关键字
random
获得随机数
sys
与解释器交互的接口
time
得到时间
1.Copy 模块
想要对某一对象进行复制时,可以使用 Python 标准库的 copy 模块。copy 模块提供了
浅拷贝、深拷贝 2 个方法实现数据复制的功能。
(1)浅拷贝
浅拷贝的语法格式如下。
语法:
copy.copy(object)
浅拷贝的作用是对内存地址的复制,目标对象和源对象指向同一片内存空间。所以当目
标对象或源对象中的内容发生改变时,都是对同一块内存进行改变,目标对象和源对象将会
同时发生改变。
示例 7:使用浅拷贝方法复制更新数据
示例代码如下:
import copy
#导入 copy 模块
class Dog:
def __init__(self,name,age,color):
self.name = name
self.age = age
self.color = color
dog1 = Dog('dog1',3,"red")
dog2 = Dog('dog2',2,"black")
dog3 = Dog('dog3',4,"green")
my_dogs = [dog1,dog2,dog3]
#源对象
more_dogs = copy.copy(my_dogs)
#复制后的目标对象
print (more_dogs[0].name)
print (more_dogs[0].color)
my_dogs[0].name="dog111"
#修改源对象的中的元素值
print ("my_dogs[0].name",my_dogs[0].name)
#输出源对象元素值
print ("more_dogs[0].name",more_dogs[0].name)
#输出目标对象元素值
#结果
>>>
dog1
red
my_dogs[0].name dog111
more_dogs[0].name dog111
示例 7 的代码中 ,先导入 copy 模块,再使用 copy.copy(my_dogs)拷贝对象。使用
my_dogs[0].name="dog111"语句对源对象中元素值进行修改后,源对象和目标对象的值依
然是相同的,因为它们指向的是同一块内存空间。
当完成浅拷贝后,再对源对象或者目标对象做增加元素的操作,是不会影响到另一方
的,这是需要特别注意的情况。
示例 8:浅拷贝后增加源对象或者目标对象的元素
示例代码如下:
import copy
class Dog:
def __init__(self,name,age,color):
self.name = name
self.age = age
self.color = color
dog1 = Dog('dog1',3,"red")
dog2 = Dog('dog2',2,"black")
dog3 = Dog('dog3',4,"green")
dog4 = Dog('dog3',4,"green")
my_dogs = [dog1,dog2,dog3]
more_dogs = copy.copy(my_dogs)
#浅拷贝
my_dogs.append(dog4)
#为源对象增加新元素
print (len(my_dogs))
print (len(more_dogs))
#结果
>>>
4
3
执行示例 8 代码,完成拷贝后,又为“my_dogs”增加了新的元素,但此时源对象的长度
是 4,而目标对象 more_dogs 的长度还是 3。说明在源对象中新增加的元素,在目标对象 中并不存在。
(2)深拷贝
copy 模块除了提供浅拷贝外,还提供有深拷贝。深拷贝的语法格式如下。
语法:
copy.deepcopy(object)
目标对象和源对象分别有各自的内存空间,内存地址是系统自动分配的,深拷贝是将源
对象的内容复制到目标对象的内存空间中。即:完成深拷贝操作后,目标对象和源对象虽然
保存的数值是相同的,但内存地址是不一样的,两个对象互不影响,互不干涉。
示例 9:
示例代码如下:
import copy
#导入 copy 模块
class Dog:
def __init__(self,name,age,color):
self.name = name
self.age = age
self.color = color
dog1 = Dog('dog1',3,"red")
dog2 = Dog('dog2',2,"black")
dog3 = Dog('dog3',4,"green")
my_dogs = [dog1,dog2,dog3]
#源对象
more_dogs = copy.deepcopy(my_dogs)
#使用深拷贝,复制后的目标对象
print (more_dogs[0].name)
print (more_dogs[0].color)
my_dogs[0].name="dog111"
#修改源对象的中的元素值
print ("my_dogs[0].name",my_dogs[0].name)
#输出源对象元素值
print ("more_dogs[0].name",more_dogs[0].name)
#输出目标对象元素值
#结果
>>>
dog1
red
my_dogs[0].name dog111
more_dogs[0].name dog1
与示例 8 不同的是,示例 9 使用 copy.deepcopy(my_dogs)进行对象的深拷贝。虽然示
例中其它代码没有变化,但输出目标对象和源对象的值却产生了变化。因为目标对象和源对
象各自占用自己的内存空间,所以,当源对象值改变后,目标对象的值并没有影响。
2.keyword 模块
使用 keyword 模块可以查看 Python 语言的关键字,它的属性 kwlist 包含了所有 Python
关键字的列表。方法 iskeyword(字符串)用于判断参数是否是 Python 的关键字。如果参数是
Python 的关键字,则返回 True;否则,返回 False。
示例 10:判断 Python 的关键字
示例代码如下:
import keyword
#导入 keyword 模块
print ("if 是 Python 的关键字吗? %s" %keyword.iskeyword("if"))
print ("duang 是 Python 的关键字吗? %s" %keyword.iskeyword("duang"))
print ("Python 的关键字列表:\n %s"%keyword.kwlist)
#结果
>>>
if 是 Python 的关键字吗? True
duang 是 Python 的关键字吗? False
Python 的关键字列表:
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise',
'return', 'try', 'while', 'with', 'yield']
示例 10 中,在导入 keyword 模块后,使用 keyword.iskeyword()方法判断字符串是否
是 Python 的关键字。而使用 keyword.kwlist 可以获得 Python 的所有关键字。
3.random 模块
random 模块用于生成随机的浮点数、整数或字符串,常用的方法如表 4-2 所示。
表 4-2 random 常用方法
方法
操作
random()
生成一个随机的浮点数,范围在 0.0~1.0 之间
uniform([上限][,下限])
在设定浮点数的范围内随机生成一个浮点数
randint([上限][,下限])
随机生成一个整数,可以指定这个整数的范围
choice(序列)
从任何序列中选取一个随机的元素返回
shuffle(序列)
随机打乱一个序列中元素的顺序
sample(序列,长度)
从指定的序列中随机截取指定长度的片断,序列本身不做修改
示例 11:使用 random 模块常用方法生成随机整数,并重新排序
示例代码如下:
import random
#导入 random 模块
print (random.randint(1,100))
#随机选取 1-100 之间的整数
print (random.randint(100,500))
#随机选取 100-500 之间的整数
list1 = ['aaa','bbb','ccc']
str1 = random.choice(list1)
#随机选取列表中一个元素
print ('随时选取列表中的一个元素:',str1)
print ('重新排序后:\n')
random.shuffle(list1)
#随机重新排序列表中的元素
for str1 in list1:
print (str1)
#结果
>>>
2
310
随时选取列表中的一个元素: ccc
重新排序后:
bbb
aaa
ccc
random 模块产生的结果都是随机的,每次运行的结果不一定相同。示例 11 中,
random.randint(1,100)方法随机返回 1 至 100 之间的一个整数,random.choice(list1)方法
随机返回列表中一个元素,而 random.shuffle(list1)方法是随机打乱列表元素的顺序。
示例 12:使用 random 模块编写一个猜数字的游戏程序
示例代码如下:
import random
print ("猜数游戏\n")
num = random.randint(1,20)
#生成 1-20 之间的一个随机整数
while True:
print ("请输入一个 1 至 20 的数字:")
i = int(input())
if i == num:
#判断输入的数字与随机数是否相等
print ("你猜对了\n")
break
elif i < num:
print ("数小了\n")
elif i > num:
print ("数大了\n")
#结果
>>>
猜数游戏
请输入一个 1 至 20 的数字:
9
数大了
请输入一个 1 至 20 的数字:
7
数小了
请输入一个 1 至 20 的数字:
8
你猜对了
示例 12 中,首先使用 random.randint(1,20)方法生成一个 1-20 之间的随机整数,然后
对用户输入的数字进行判断大小。如果两数相等,则程序退出;否则,将提示用户“数大了”
或者“数小了”。
4.sys 模块
sys 模块包含与 Python 解释器和运行环境相关的属性和方法,常用的属性和方法如表
4-3 所示。
表 4-3 sys 模块常用属性和方法
属性/方法
操作
version
获取解释器的版本信息
path
获取模块的搜索路径,初始化时使用 PYTHONPATH 环境变量的
值
platform
获取操作系统平台名称
maxint
最大的 int 值
maxunicode
最大的 Unicode 值
stdin
读取信息到 Shell 程序中
stdout
向 Shell 程序输出信息
exit()
退出 Shell 程序
示例 13:
示例代码如下所示:
import sys
#导入 sys 模块
print ("Python version:%s" %sys.version)
print ("Python platform:%s" %sys.platform)
print ("Python path:%s" %sys.path)
str = sys.stdin.readline()
#实现标准输入,默认输入的格式是字符串
print (str)
sys.stdout.write("duang!!!\n")
sys.stdout.write(str)
sys.exit()
#结果
>>>
Python version:3.6.5 (default, Jul 23 2018, 15:42:53)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
Python platform:linux
Python
path:['/root','/usr/local/python3/lib/python36.zip',
'/usr/local/python3/lib/python3.6','/usr/local/python3/lib/python3.6/lib-dynload',
'/usr/local/python3/lib/python3.6/site-packages']
wyjx double kill!
#此行手动输入内容
wyjx double kill!
duang!!!
wyjx double kill!
前面几个都是 Python 相关的一些属性,“sys.stdin.readline()”是接收键盘的输入,
“stdout.write()”是输出信息到屏幕,是对系统标准输入输出的调用 。“sys.exit()“是退出 Shell
程序。
5.time 模块
time 模块包含各种操作时间的方法,常用方法如表 4-4 所示。
表 4-4
time 模块的方法
属性/方法
操作
time()
获取当前时间戳
localtime()
获取当前时间的元组形式
ctime()
获取当前时间的字符串形式
asctime(t)
将时间转换成字符串,参数 t 是元组形式的时间
sleep(secs)
按指定的时间推迟运行,参数是推迟的时间,单位是秒
Python 中时间有时间戳和元组两种表示形式。时间戳的表现形式是以相对 1970.1.1
00:00:00 为起点,以秒计算的偏移量,是唯一的值。而以元组的形式表示则共有 9 个元
素,分别是 year(4 位数字组成)、month(1-12)、day(1-31)、hours(0-23)、minutes(0-59)、
second(0-59)、weekday(0-6,0 表示周一)、Julian day(1-366,一年里的天数)、DST flag(-1,
0 或 1,是否是夏令时,默认为-1)。
示例 14:用 time 模块的 time()方法,以时间戳的形式计算程序代码执行的时间
示例代码如下:
import time
print (time.time())
def lots_of_numbers(max):
t1 = time.time()
#循环执行前的开始时间戳
for x in range(0,max):
print (x)
t2 = time.time()
#循环执行后的结束时间戳
print ("程序运行了%d 秒" % (t2-t1))
#执行循环用了多少时间
lots_of_numbers(1000)
#结果
1593757369.8253443
#省略内容
程序运行了 0 秒
使用“time.time() ”获得的是以秒为单位的偏移量,在 for 循环开始处获得时间戳,循环
结束时再获得时间戳,相减后就是循环执行的时间。
示例 15:以元组的形式获取时间,示例代码如下:
import time
print (time.time())
#获取时间戳
print (time.asctime())
#时间的字符串形式
print (time.localtime())
#时间的元组形式
t1 = (2015,9,29,10,30,12,12,12,0)
print (time.asctime(t1))
#把时间的元组形式转换为字符串形式
t2 = time.localtime()
year = t2[0]
#获得时间元组中的年份
print (year)
for i in range(1,5):
print (i)
time.sleep(1)
#推迟 1 秒,再向后运行
#结果
1593757569.4021692
Fri Jul 3 14:26:31 2020
time.struct_time(tm_year=2020, tm_mon=7, tm_mday=3, tm_hour=14, tm_min=26, tm_sec=59,
tm_wday=4, tm_yday=185, tm_isdst=0)
Sat Sep 29 10:30:12 2015
2020
12
3
4
示例 15 中,使用“time.localtime() “可以获得元组形式的时间,需要任何时间的值只需
要去元组中找对应的元素即可。” time.sleep(1)”的作用是使程序推迟 1 秒再继续运行,输出
数字时可以看到,是在停止 1 秒后再显示下一个数字。
4.3 文件和目录操作
文件与目录操作是编程语言中非常重要的功能,Python 也对其提供了相应的 API 支持。
4.3.1 文件操作
1.计算机文件
在计算机系统中,以硬盘为载体存储在计算机上的信息集合称为文件。文件可以是文本
文档、图片、声音、程序等多种类型。在编程时经常要对文件进行读写等操作,从程序员的
视角可以把文件理解为是连续的字节序列,进行数据传输需要使用字节流,字节流可以是由
单个字节或大块数据组成。文件类型通常分为文本文件和二进制文件。
2.文件打开和关闭操作
对文件进行操作在 Python 中分为 3 个步骤,首先要打开文件,然后是对文件进行读写
操作,最后需要关闭文件。
(1)打开文件操作
打开文件使用的是 open()函数,它提供初始化输入、输出(I/O)操作的通用接口,打
开文件成功后返回一个文件对象,打开失败则引发一个错误。打开文件的语法如下。
语法:
file_object = open(file_name,access_mode [,buffering])
file_name 是要打开的文件名,可以是文件的相对路径或绝对路径。绝对路径是文件在
硬盘上真正存在的路径,如”/home/python”是绝对路径。相对路径是相对于当前运行程序所
在路径的目标文件位置,表示相对路径时,“.”表示当前的位置,”..”表示当前位置的上一级,
如”../images”或”./DB”是相对路径。使用相对路径的好处是,当程序迁移时,由于绝对路径
与本地计算机关联紧密,程序运行可能会出错,所以,通常是使用相对路径。
access_mode 表示文件打开的模式,常用模式如表 4-5 所示。
表 4-5 打开模式参数说明
模式
操作
说明
r
读取
文件必须存在
w
写入
如果文件存在,要先清空其中的数据,再重新创建
a
追加
如果文件不存在,先自动创建文件。所有写入的数据都将追加
到文件的末尾
b
二进制文件
不能作为第 1 个字符出现
x
创建新文件
如果是新文件则可写入内容,如果文件已存在,将会报错
+
更新磁盘文件
读写
r 表示的是对文件进行读取操作,w 表示写入数据到文件中,a 是追加数据到文件的末
尾,b 是标识文件为二进制文件,与 rwa 组合使用,如打开音视频等二进制文件需要使用 b
模式。不指定模式时默认是 r 模式。
buffering 表示访问文件采用的缓冲方式。0 表示不缓冲,1 表示只缓冲 1 行,任何大于
1 的值表示按给定值作为缓冲区大小,不提供该参数或给定负值表示使用系统默认缓冲机
制。
(2)关闭文件操作
对文件进行读写等操作后需要关闭文件,目的是释放文件占用的资源。使用的是
file.close()方法,file 表示的是已打开的文件对象。如果不显式的关闭文件,Python 的垃圾
收集机制也会在文件对象的引用计数为 0 时自动关闭文件,但是可能会丢失输出缓冲区的
数据。如果不及时关闭已经打开的文件,该文件资源会被占用,将无法对该文件执行其他操
作,如删除文件的操作。所以要养成良好的编程习惯,在完成文件操作后,要及时关闭文件,
释放资源。
示例 16:打开和关闭文件
示例代码如下:
fp = open('/usr/local/readme.txt','x')
#绝对路径,写文件
fp.close()
fp = open('./readme.txt','r')
#相对路径,读文件
fp.close()示例 16 中,第一个 open()函数是使用绝对路径,“x”表示对文件创建并进行的写操作。
在使用该参数时,如果文件已存在,那么将会返回错误。第二个 open()函数是使用相对路
径,在当前 Python 文件的目录下查找,”r”表示读取。如果找不到则会出错,找到则会读取
文件。
3.向文件中写入数据
打开文件后可以把表示文本数据或二进制数据块的字符串写入到文件中。Python 提供
了两个方法,一个是 file.write(str),str 表示一个字符串;另一个是 file.writelines(seq),seq
表示字符串序列,实际上是字符串的元组或列表。使用时需要注意,行结束符并不会自动写
入到文件中,需要在每行的结尾加上行结束符“\n”。
示例 17:打开文件并向文件中写数据
示例代码如下:
fp = open('/usr/local/readme.txt','w')
fp.write("write1")
fp.write("write2\n")
fp.writelines(["writelines1\n","writelines2\n"])
fp.close()
#查看生成的文本文件/usr/local/readme.txt 中的内容
write1write2
writelines1
writelines2
从示例 17 程序执行结果可以发现,第一个 fp.write("write1")参数中字符串后面没有加
入”\n”,文件内容中没有换行。fp.write("write2\n")有换行符,后面的内容就在下一行显示。
fp.writelines(["writelines1\n","writelines2\n"])使用列表输出,都有换行符,所以在不同行显
示。
4.从文件中读取数据
读取文件中的数据有多种方式,可以直接读取字节,可以读取一行数据,还可以读取剩
余的行数据。
(1)读取字节
使用 file.read()方法可以读取字节,它可以指定数值参数,表示以当前位置开始要读取
的字节数,也可以不指定数值参数,表示以当前位置开始到文件结尾的所有字节。可以使用
字符串变量接收它的返回值。
示例 18:文件中写入数据,并使用 fp.read()方法按字节读取
示例代码如下:
fp = open('/usr/local/readme.txt','w')
#写入数据
fp.writelines(["01234\n","56789\n"])
fp.close()
fp = open('/usr/local/readme.txt','r')
#读取数据
print ("fp.read(3)")
print (fp.read(3))
print ("fp.read(5)")
print (fp.read(5))
print ("fp.read()")
print (fp.read())
fp.close()
#显示结果
fp.read(3)
012
fp.read(5)
34
56
fp.read()
789
首先写入了一个数据文件,第一行内容是”01234”,第二行是”56789”,实际上每行还有
一个换行符,总共是 12 个字符。读取文件时,先使用 read(3)读取,表示从文件起始位置
到第 3 个字符,所以输出结果是“012”。然后使用 read(5)读取,此时就不是从文件起始位置
开始,而是从上一次未读取的字符开始取后面的 5 个字符,所以输出是“34\n56”,包括换行
符共 5 个字符。最后使用 read()读取,就是未读取的所有字符“789”。
(2)读取一行数据
使 用 file.readline() 可 以 读 取 一 行 数 据 , 同 样 是 返 回 一 个 字 符 串 。 还 可 以 使 用
file.readlines()读取剩余的行数据,返回的是一个字符串列表。示例 19:文件中写入数据,使用 file.readlines()方法以行为单位读取数据
示例代码如下:
fp = open('/usr/local/readme.txt','w')
fp.writelines(["01234\n","56789\n","abcde"])
fp.close()
fp = open('/usr/local/readme.txt','r')
print ("readline():")
print (fp.readline())
print ("readlines():")
print (fp.readlines())
fp.close()
#显示结果
readline():
01234
readlines():
['56789\n', 'abcde']
往文件中写入了三行数据,使用 readline()时读取了第 1 行数据,然后使用 readlines()
读取了剩余的 2 行,返回字符串的列表。实际编程时需要注意,按行读取时速度很快,但
文件较大时读取所有行就会很慢。
(3)文件的读写方式
以写方式打开文件时,不支持读操作,但是还有其它几种模式存在,使用 r+、w+、或
a+方式打开文件,可以同时进行读写操作。r+表示不清除原文件内容,读写方式打开,而
新添加的数据在文件尾部。w+表示清除原文件内容,读写方式打开,读不到原文件的内容。
a+表示把文件指针移到文件末尾,在文件末尾可以继续写数据,读数据不受影响。
(4)迭代器与文件迭代
从 Python2.2 开始,引进了迭代器和文件迭代,使文件操作更高效,不再需要调用 read()
方法。迭代就是在 for 循环中读取每一行数据。
示例 20:文件中写入数据,使用迭代读取每一行数据
示例代码如下:
fp = open('/usr/local/readme.txt','w')
fp.writelines(["01234\n","56789\n","abcde"])
fp.close()
fp = open('/usr/local/readme.txt','r')
for eline in fp:
print (eline)
fp.close()
#显示结果
01234
56789
abcde
在示例 20 的 for 循环中 fp 表示打开的文件,eline 表示迭代的每行数据,包含末尾的行
结束符,这样对文件的读取更容易操作。
5. 文件指针
前面讲到的文件操作是按顺序进行读取,在 Python 中实际上是用指针实现的。指针是
指向文件中数据的位置。当打开文件后,指针是指向文件的开始处。当读取一定的数据后,
指针后移到未读取的位置,再读取时就以指针为开始位置向后继续移动。默认情况下,指针
是从左向右,从上至下移动,且文件指针不能自动往回移动。
Python 提供了移动指针的方法 file.seek(offset,whence=0),使对文件的操作可以灵活
控制。参数 offset 是相对于某个位置的偏移量,以字节为单位。当 offset 为正数时,表示从
前向后移动指针。当 offset 为负数时,表示从后向前移动指针。参数 whence 指定偏移前的
位置 0(SEEK_SET)表示文件开始处;1(SEEK_CUR)表示指针的当前位置;2(SEEK_END)
表示文件末尾处。获得指针当前位置的方法是 file.tell(),它是从文件起始位置开始计算,也
是以字节为单位。
示例 21 使用指针操作文件
示例代码如下:
fp = open('/usr/local/readme.txt','w')
fp.writelines("123456789")
fp.close()
fp = open('/usr/local/readme.txt','rb')
print ("指针移动的起始位置是:",fp.tell())
fp.seek(3)
print ("向后移动 3 个字节后位置是:",fp.tell())
print (fp.read(3))
print ("读取 3 个字节后位置是:",fp.tell())
fp.seek(-4,1)
print ("向前移动 4 个字节后位置是:",fp.tell())
print ("指针后所有数据是:",fp.read())
fp.close()
#结果
指针移动的起始位置是: 0
3
向后移动 3 个字节后位置是: 3
b'456'
读取 3 个字节后位置是: 6
2
向前移动 4 个字节后位置是: 2
指针后所有数据是: b'3456789'
示例 21 中,使用”w”模式写入数据后,以“rb”模式打开文件。指针默认的起始位置是开
头,也就是 0。
f
p.seek(3)使指针向后移动 3 个字节,指针是指向文件中的字符“3”,
f
p.read(3)
读取 3 个字节,所以输出是“456”。这时指针的当前位置是 6,指向文件中的字符“6”,使用
fp.seek(-4,1)是在当前位置向前移动 4 个字节,此时指针指向字符“2”,最后 fp.read()输出“2”
之后的所有内容。
6. 常用的文件对象内建方法
文件对象的操作方法有很多,常用的方法总结如表 4-6 所示。
表 4-6 文件对象的操作方法
方法
操作
open()
创建并打开文件
file.close()
关闭文件
file.fileno()
返回文件的描述符
file.read(size=-1)
从文件读取 size 个字节,当未给定 size 或给定负值时,读取剩余的
所有字节,作为字符串返回
file.readline(size=-1)
从文件中读取并返回一行(包括行结束符),或返回最大的 size 个
字符
file.readlines(sizehint=0)
读取文件的所有行并作为一个列表返回(包括所有的行结束符)。如
果给定 sizehint 且大于 0,将返回总和大约为 sizehint 字节的行
file.seek(off,whence=0)
在文件中移动文件指针,从 whence 偏移 off 字节。其值 0 代表文件
开始,1 代表当前位置,2 代表文件末尾
file.write(str)
向文件写入字符串
file.writelines(seq)
向文件写入字符串序列 seq
4.3.2 目录操作
使用 Python 的 OS 模块可以进行目录操作。
(1)获取当前路径是经常会用到的方法,可以使用 getcwd()函数,示例代码如下:
import os
print (os.getcwd())
使用 listdir(path)可以获得目录下面的所有文件的目录列表,示例代码如下:
import os
print (os.listdir(os.getcwd()))
(2)创建新的目录可以使用 mkdir(path)函数,示例代码如下:
import os
print (os.mkdir('test'))
默认目录创建在当前目录下,也可以指定全路径进行创建。
删除目录可以使用 rmdir(path),示例代码如下:
import osprint (os.rmdir('test'))
(3)判断目录是否存在使用 path.isdir(path),示例代码如下:
import os
print (os.path.isdir('test'))
(4)判断是否是文件可以使用 path.isfile(path) ,示例代码如下:
import os
print (os.path.isfile('test'))