使用Python处理文件

数据的存储可以使用数据库,也可以使用文件。数据库保持了数据的完整性和关联性,而且使数据更安全、可靠。使用文件存储数据则非常简单、易用,不必安装数据库管理系统等运行环境。文件通常用于存储应用软件的参数或临时性数据。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 + ' '


版权声明:本文为zoinsung_lee原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。