数据的存储可以使用数据库,也可以使用文件。数据库保持了数据的完整性和关联性,而且使数据更安全、可靠。使用文件存储数据则非常简单、易用,不必安装数据库管理系统等运行环境。文件通常用于存储应用软件的参数或临时性数据。Python的文件操作和Java的文件操作非常相似。Python提供了os、os.path等模块处理文件。
- 文件的创建、读写和修改
- 文件的复制、删除和重命名
- 文件内容的搜索和替换
- 文件的比较
- 配置文件的读写
- 目录的创建和遍历
- 文件的流
一、文件的常见操作
文件通常用于存储数据或应用系统的参数。
1.1 文件的创建
文件的打开或创建可以使用函数open()。该函数可以指定处理模式。open()的声明如下:
open(file,mode='r',buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)
参数file是被打开的文件名称。如果文件不存在,open()将创建名为name的文件,然后再打开该文件。
参数mode是指文件的打开模式
参数buffering设置缓存模式。0表示不缓存;1表示行缓冲;如果大于1则表示缓冲区的大小,以字节为单位。
open()返回1个file对象,file对象可以对文件进行各种操作。
文件的打开模式:
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
w 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
w+ 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
注意:对于图片、视频等文件必须使用“b”的模式读写。
file类用于文件管理,可以对文件进行创建、打开、读写、关闭等操作。
file类的常用属性和方法:
f.close() 关闭文件对象f,并将属性f.closed设置为True
f.closed 文件已关闭,则返回True
f.encoding bytes与str之间进行转换时使用的编码
f.fileno() 返回底层文件的文件描述符(只对那些有文件描述符的文件对象是可用的)
f.flush() 清空文件对象f,并将缓存中的内容写入磁盘(如果有)
f.isatty() 如果文件对象与控制台关联,就返回True(只有在文件对象应用了真正的文件时才是可用的)
f.mode 文件对象打开时使用的模式
f.name 文件对象f的文件名(如果有)
f.newlines 文件文件f中的换行字符串的类型
f.next() 返回文件对象f的下一行,大多数情况下,这种方法是隐式地使用的,比如对f中的行返回n个字节,而不移动文件指针的位置
f.peek(n) 返回n个字节,而不移动文件指针的位置
f.read(count) 从文件对象f中读取至多count个字节,如果没有指定count,就读取从当前文件指针直至最后的每个字节。以二进制模式读时,返回bytes对象;以文本模式读时,返回str对象。如果没有要读的内容(已到文件结尾),就返回一个空的bytes或str对象
f.readable() 如果f已经打开等待读取,就返回True
f.readinto(ba) 将至多len(ba)个字节读入到bytearray ba中,并返回读入的字节数——如果在文件结尾,就为0(只有在二进制模式时才是可用的
f.readline(count) 读取下一行(如果指定count,并且在\n字符前满足这一数值,那么至多读入count个字节),包括\n
f.readlines(sizehint) 读入到文件结尾之前的所有行,并以列表形式返回。如果给定sizehint,那么至多读入大概sizehint个字节(如果底层文件对象支持)(这里有点问题,os有一属性DEFAULT_BUFFER_SIZE,其大小为8192(8K)字节,readlines()函数在每次读入的大小大约为DEFAULT_BUFFER_SIZE的一个近似值,并不是读入所有内容。)
f.seek(offset,whence) 如果没有给定whence,或其为os.SEEK_SET,就按给定的offset移动文件指针(并作为下一次读、写的起点);如果whence为os.SEEK_CUR,就相对于当前文件指针位置将其移动offset(可以为负值)个位置(whence为os.SEEK_END,则是相对文件结尾).在追加”a”模式下,写入总是在结尾处进行的,而不管文件指针在何处.在文本模式下,只应该使用tell()方法的返回值作为offset
f.seekable() 如果f支持随机存取,就返回True
f.tell() 返回当前指针位置(相对文件起始处)
f.truncate(size) 截取文件到当前文件指针所在位置,如果给定size,就到size大小处
f.writable() 如果f是为写操作而打开的,就返回True
f.write(s) 将bytes/bytearray对象s写入到文件(该文件以二进制模式打开),或者将str对象s写入到文件(该文件以文本模式打开)
f.writelines(seq) 将对象序列(对文本文件而言是字符串,对二进制文件而言是字节字符串)写入到文件)
文件的处理一般分为以下3个步骤:
(1)创建并打开文件,使用file()函数返回一个file对象。
(2)调用file对象的read()、write()等方法处理文件。
(3)close()关闭文件,释放file对象占用的资源。
context = '''hello world'''
f = open('hello.txt','w') #打开文件,调用open()创建文件hello.txt,设置文件的访问模式为“w”,open()返回文件对象f
f.write(context) #把字符串写入文件,把变量的context的值写入文件hello.txt中
f.close() #关闭文件,调用close()方法释放对象f占用的资源
print("文件写入完毕!!!")
1.2文件的读取
按行读取方式readline()
#使用readline()读取文件
f = open('hello.txt','r')
while True: #使用Ture构成永真式
i = 1
# line = f.readline() #调用readline()读取hello.txt文件中的每一行
line_else = f.readline(2) #调用readline(2)读取hello.txt文件中每行每次2个字节的内容,直到行的末尾
if line_else : #判断循环是否停止,如果文件指针到文件末尾则跳出循环
print(line_else)
else:
print('文件读写完毕!!!使用readline()读取')
break
i += 1
f.close()
多行读取方式readlines()
#使用readlines()读文件
f = open('hello.txt')
lines = f.readlines() #调用readlines(),把文件hello.txt中
print("\n使用readlines()读取",lines)
for line in lines:
print(line)
print("部分读取!!使用readlines()读取")
f.close()
一次性读取方式read()
#使用read()读文件
f = open('hello.txt')
context = f.read() #调用read(),把文件hello.txt中所有的内容存储在变量context中
print("使用read()读取\n",context)
f.close()
通过参数控制read()参数的值:
#通过参数控制,返回指定字节的内容
f = open('hello.txt')
context = f.read(5) #调用read(5),读取hello.txt文件中前5个字节的内容。
print("通过参数控制输出",context)
print("文件指针的当前位置",f.tell()) #此时文件指针移到第5字节处
context = f.read(5) #再次调用read(5),读取第6个字节到第10个字节的内容
print("通过参数控制输出",context)
print("文件指针的当前位置",f.tell()) #文件指针的当前位置为10
f.close()
注意:file对象内部将记录文件指针的位置,以便下次的操作。只要file对象没有执行close()方法,文件指针就不会释放。
1.3文件写入
使用writelines()写文件
#使用writelines()将列表内容写入文件
f = open('hello.txt','w+') #使用“w+”模式创建并打开文件hello.txt
li = ['hello world\n','hello world\n']
f.writelines(li)
f.close()
追加新的内容到文件
#追加新的内容到文件中
f = open('hello.txt','a+') #使用“a+”模式打开文件
new_context = 'goodbye' #调用write()方法,hello.txt文件的原有内容保持不变,把变量new_context的内容写入hello.txt文件的末尾
f.write(new_context)
f.close()
1.4文件的删除
文件的删除需要使用os模块和os.path模块。os模块提供了对系统环境、文件、目录等操作系统级的接口函数。
os模块常用的文件处理函数:
os.sep可以取代操作系统特定的路径分隔符。windows下为 “\”
os.name字符串指示你正在使用的平台。比如对于Windows,它是’nt’,而对于Linux/Unix用户,它是’posix’。
os.getcwd()函数得到当前工作目录,即当前Python脚本工作的目录路径。
os.getenv()获取一个环境变量,如果没有返回none
os.putenv(key, value)设置一个环境变量值
os.listdir(path)返回指定目录下的所有文件和目录名。
os.remove(path)函数用来删除一个文件。
os.system(command)函数用来运行shell命令。
os.linesep字符串给出当前平台使用的行终止符。例如,Windows使用’\r\n’,Linux使用’\n’而Mac使用’\r’。
os.path.split(p)函数返回一个路径的目录名和文件名。
os.path.isfile()和os.path.isdir()函数分别检验给出的路径是一个文件还是目录。
os.path.existe()函数用来检验给出的路径是否真地存在
os.curdir:返回当前目录(’.’)
os.chdir(dirname):改变工作目录到dirname
os.path.getsize(name):获得文件大小,如果name是目录返回0L
os.path.abspath(name):获得绝对路径
os.path.normpath(path):规范path字符串形式
os.path.splitext():分离文件名与扩展名
os.path.join(path,name):连接目录与文件名或目录
os.path.basename(path):返回文件名
os.path.dirname(path):返回文件路径
文件的删除操作:
import os #文件的删除需要使用os模块和os.path模块
open('hello_del.txt','w') #创建文件hello.txt
if os.path.exists('hello.txt'): #调用os.path模块的exists()函数判断文件是否存在
os.remove('hello.txt') #调用remove()删除文件
1.5文件的复制
file类并没有提供直接复制文件的方法,但是可以使用read()、write()方法,同样可以实现复制文件的功能。
#使用read()、write()实现文件复制
#创建文件hello.txt
src = open('hello.txt','w')
li = ['hello world\n','hello China\n']
src.writelines(li)
src.close()
#把hello.txt复制到hello2.txt中
src = open('hello.txt','r') #以只读方式打开文件
dst = open('hello2.txt','w') #以只写方式打开文件
dst.write(src.read()) #将文件hello.txt文件中的内容写入hello2.txt文件中
print("文件复制完毕!!")
# print(dst.read())
src.close()
dst.close()
f = open('hello2.txt','r')
print(f.read())
print("文件hello2.txt读取完毕!!")
f.close()
使用shutil模块实现文件的复制:
#shutil模块实现文件的复制
import shutil
shutil.copy('hello.txt','hello2.txt') #复制文件
shutil.move('hello.txt','../') #将文件复制到父级目录,实现文件的剪切
shutil.move('hello2.txt','hello3.txt') #将hello2。txt文件移动到当前目录,并命名为hello3.txt,hello2.txt文件将被删除
1.6文件的重命名
os模块的函数rename()可以对文件或目录进行重命名。
import os
li = os.listdir('.') #调用listdir()返回当前目录的文件列表,其中‘.表示当前目录’
print(li)
#判断文件名是否在目录列表中
if 'hello.txt' in list:
os.rename('hello.txt','hi.txt')
elif 'hi.txt' in list:
os.rename('hi.txt','hello.txt')
修改文件格式:
import os
files = os.listdir('.') #获取当前目录下的所有文件
for filename in files:
li = os.path.splitext(filename) #调用split()对文件名进行解析,返回文件名和后缀名组成的列表
if li[1] == '.html': #判断文件是否以html结尾
newname = li[0]+'.htm' #重新组合新的文件名
os.rename(filename,newname)
1.7文件内容的搜索和替换
从hello.txt中统计字符串“hello”的个数:
import re
#统计文件中字符串的“hello”个数
f1 = open('hello.txt','r') #打开文件
count = 0 #变量count统计hello的个数
for s in f1.readlines():
li = re.findall('hello',s) #在读取的内容中查找hello
if len(li)>0: #判断获取的结果中是否有hello
count = count + li.count() #将本次内容中hello的个数计入变量count中
print("找到了%d个hello",count)
f1.close()
1.8文件的比较
Python提供了模块difflib,实现对序列、文件的比较。如果要比较两个文件,列出两个文件的异同,可以使用difflib模块的SequenceMatcher类实现,其中的get_opcodes()可以返回两个序列比较的结果。
比较两个文件,并返回比较结果:
import difflib
f1 = open('hello.txt','r')
f2 = open('hi.txt','r')
src = f1.read()
dst = f2.read()
print(src)
print(dst)
s = difflib.SequenceMatcher(lambda x:x ==' ',src,dst) #生成序列匹配对象,其中的lambda表示忽略hi.txt中的换行符,如果hi.txt中有多余的换行,并不会作为不同点返回
for tag ,i1,i2,j1,j2 in s.get_opcodes(): #获取比较结果
print("%s src[][%d:%d]=%s dst[%d:%d]=%s"%(tag,i1,i2,src[i1:i2],j1,j2,dst[j1:j2]))
1.9配置文件的访问
再应用程序中通常使用配置文件定义一些参数,Windows的ini文件就是一种传统的配置文件,ini文件由多个块组成的,每个块由多个配置项组成。
#读配置文件
import configparser
config = configparser.ConfigParser() #创建一个ConfigParser对象
config.read("ODBC.ini") #读取ODBC.ini文件
sections = config.sections() #调用sections()返回配置块的标题
print("配置块:",sections)
o = config.options("OBDC 32 bit Data Sources") #调用options()
print("配置项:",o)
#写配置文件
config.add_section("ODBC Driver Count") #添加新的配置块
config.set("ODBC Driver Count","count",2) #添加新的配置项,并设置其内容
f = open("ODBC.ini","a+") #以a+模式打开文件ODBC.ini,追加新的配置
config.write(f) #写配置文件
f.close()
#修改配置文件
config.read("ODBC.ini")
config.set("OBDC Driver Count","count",3) #修改配置项
f = open("ODBC.ini","r+")
config.write(f)
f.close()
#删除配置文件
config.read("ODBC.ini")
config.remove_option("ODBC Driver Count","Count") #删除配置项
config.remove_section("ODBC Driver Count") #删除配置块
f = open('ODBC.ini','w+')
config.write(f)
f.close()
二、目录
2.1目录的创建和删除
os模块常用的目录处理函数:
getcwd() 返回当前工作目录
chdir(path) 改变工作目录
listdir(path=’.’) 列举指定目录中的文件名(’.’表示当前目录,’..’表示上一级目录)
mkdir(path) 创建单层目录,如该目录已存在抛出异常
makedirs(path) 递归创建多层目录,如该目录已存在抛出异常,注意:’E:\a\b’和’E:\a\c’并不会冲突
remove(path) 删除文件
rmdir(path) 删除单层目录,如该目录非空则抛出异常
removedirs(path) 递归删除目录,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常
rename(old, new) 将文件old重命名为new
system(command) 运行系统的shell命令
walk(top) 遍历top路径以下所有的子目录,返回一个三元组:(路径, [包含目录], [包含文件])
os.curdir 指代当前目录(’.’)
os.pardir 指代上一级目录(’..’)
os.sep 输出操作系统特定的路径分隔符(Win下为’\’,Linux下为’/’)
os.linesep 当前平台使用的行终止符(Win下为’\r\n’,Linux下为’\n’)
2.2目录的遍历
目录的遍历有两种实现方法:递归函数、os.walik()
(1)递归函数:
import os
#定义递归函数遍历文件目录
def VisitDir(path):
li = os.listdir(path) #获取path路径下的文件目录和文件名
for item in li : #遍历
pathname = os.path.join(path,item) #生成目录或者文件的绝对路径
if not os.path.isdir(pathname): #如果pathname不是文件名,则递归调用遍历子目录
VisitDir(pathname)
else:
print(pathname)
if __name__ == "__main__":
path = r"D:\python_demo"
VisitDir(path)
使用os.walk()遍历目录:
import os
def VisitDir(path):
for root,dirs,files in os.walk(path): #os.walk(path)函数返回三个元素,路径名、目录列表、文件列表
for filepath in files:
print(os.path.join(root,filepath))
if __name__ == "__main__":
path = r"D:\python_demo"
VisitDir(path)
三、文件和流
读写数据的方式有多种,如文件的读写、数据库的读写。为了有效地表示数据地读写,把文件、外设、网络连接等数据传输抽象地表示为流。数据地传输就好像流水一样,从一个容器流到另一个容器。
3.1Python中地流对象
Python隐藏了流机制,Python把文件的处理和流关联在一起,流对象实现了File类的所有的方法,sys模块提供了3种基本的流对象——stdin、stdout、stderr。这三个对象分别表示标准输入、标准输出和错误输出。流对象的处理方式和文件的处理方式相同。
(1)stdin
对象stdin表示流的标准输入:
import sys
sys.stdin = open('hello.txt','r')
for line in sys.stdin.readlines():
print(line)
(2)stdout
对象stdout表示流的标准输出,前面的程序都是把程序运行后的结果输出到控制台,这里通过stdout对象重定向输出,把输出结果保存到文件中。
import sys
sys.stdout = open('hello.txt','a') #将hello.txt设置为终端输出设备,默认的终端输出设备是系统的控制台
print('goodbye') #想文件中输出字符串
sys.stdout.close()
(3)stderr
日志文件通常用于记录应用程序每次操作的执行结果。Python的stderr对象用于记录、输出异常信息,通过stderr对象可以实现日志文件的功能。
import sys,time
sys.stderr = open('record.log','a') #将输出终端重定向到recor.log文件
f = open('hello.txt','r') #打开hello.txt文件
t = time.strptime('%Y-%m-%d %X',time.localtime()) #获取当地时间,并将其转化为字符串格式
content = f.read() #读取文件内容
if content: #如果有内容,则将当地时间和文件内容写入日志文件中
sys.stderr.write(t+" "+content)
else:
raise (Exception,t+'异常信息') #如果文件为空,则抛出异常,并将当地时间和异常提示信息写入日志文件中
3.2模拟Java的输入和输出
模拟Java的输入、输出流读写文本文件:
#定义文件输入流
def FileInputStream(filename):
try:
f = open(filename) #打开文件
for line in f: #读出文件中的每行数据
for byte in line: #读出文件中的每行中的每个字节的数据
yield byte #采用Genertor函数的风格设计,模拟Java的FileInputStream类的工作方式,使用yield关键字,返回文件每个字节的数据
except StopIteration.e:
f.close() #如果抛出异常,则关闭文件
return
def FileOutStream(inputStream,filename):
try:
f = open(filename,'w')
while True:
byte = inputStream.next() #获取FileInputStream(filename)中产生的字节
f.write(byte)
except StopIteration.e:
f.close() #如果抛出异常,则关闭文件
return
if __name__ == "__main__":
FileOutStream(FileInputStream('Hello.txt'),'hello2.txt')
四、文件属性浏览程序
设计一个函数showFileProperties(path),path代表目录的路径,该函数可以查看path目录下所有文件的属性。
#1.遍历path指定的目录,获取每个子目录的路径
#2.遍历子目录下的所有文件,并返回文件的属性列表
#3.分解属性列表,对属性列表的值进行格式化输出
import os,time
def showFileProperties(path):
for root,dirs,files in os.walk(path,Ture): #获取路径目录中的子目录和文件
print('位置:',root) #输出路径
for filename in files: #遍历文件名
state = os.stat(os.path.join(root,filename)) #获取文件属性列表,os.stat()函数参数必须是绝对路径,因此,需要先调用os.path.join()连接路径和文件名
info = "文件名 "+filename+" "
info = info +"大小:"+('%d'%state[-4]) +" "
t = time.strptime('%Y-%m-%d %X',time.localtime(state[-1]))
info = info + "创建时间: " + t +' '
t = time.strptime('%Y-%m-%d %X', time.localtime(state[-2]))
info = info + "最后修改时间: " + t + ' '
t = time.strptime('%Y-%m-%d %X', time.localtime(state[-3]))
info = info + "最后访问时间: " + t + ' '