Python入门(八):对象类型之文件

本文深入探讨Python中的文件操作,从基础知识到open()函数的详细使用,涵盖文件的打开、读写操作。介绍了文本文件和二进制文件的区别,以及pickle模块在存储Python原生对象中的应用,还有struct模块在处理打包二进制数据上的使用。
部署运行你感兴趣的模型镜像

1. 文件和文件对象

1.1 基础知识

  文件是存储在某种长期储存介质的数据流。这些数据被操作系统管理,并且被操作系统会组织成文件系统。文件都带有名字并放在特定的文件夹或目录中。Python需要与文件建立连接,才能对文件进行操作。Python使用内置的open()函数打开文件,返回一个可以处理的文件对象(file object),这样就可以通过调用返回文件对象的方法来读写相关外部文件。

  Python中共有三种类别的文件对象: 原始二进制文件, 缓冲二进制文件 以及 文本文件。它们的接口定义均在 io 模块中。注意:Python不依赖于底层操作系统的文本文件概念;所有处理都由Python本身完成,因此与平台无关。 Python处理的文件类型由open()函数的第二个参数决定。

  • 二进制文件和文本文件

  二进制文件就是第二个参数 (模式字符串) 包含一个'b'打开的文件。文本文件实际是访问一个面向字节的数据流并自动处理 text encoding。文本文件的例子包括以文本模式('r''w')打开的文件。二进制文件把内容表示为一个特殊的Bytes字符串类型,并且允许程序不修改地访问文件内容;文本文件把内容表示为常规的str字符串,自动执行Unicode编码和解码,并且默认执行末行转换。

1.2 文件的基本操作

1.2.1 open()函数详解

open()函数: 打开文件,返回一个文件对象,如果文件不能够打开,会返回OsError.

open( file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
file 是一个路径类对象,表示打开文件的路径 ( 绝对路径或者当前工作目录的相对路径 ) 或者一个非负整数的文件描述符。

mode 是模式字符串,指定打开文件的模式。默认值是'r' ,这意味着它以文本模式打开并读取。常见的模式字符串如下:

模式字符串意义
r读取模式(默认)
w写入模式,并先截断文件(文件内容清空)
a写入模式,如果文件存在,则在末尾追加内容
x排他性创建模式,如果文件存在则失败
b二进制模式
t文本模式(默认)
+更新磁盘文件(读取并写入)

在文本模式,如果 encoding 没有指定,则根据平台来决定使用的编码,查看当前平台使用的编码可以使用locale.getpreferredencoding(False)

>>> import locale
>>> locale.getpreferredencoding(False)
'UTF-8'

像之前提到的二进制文件和文本文件,以二进制模式打开的文件返回的内容为 bytes对象,不进行任何解码。在文本模式下,文件内容返回为 str ,首先使用指定的 encoding 或者使用平台默认的的字节编码解码。

buffering是一个可选的整数,用于设置缓冲策略。传递0以切换缓冲关闭(仅允许在二进制模式下),也就是调用写入方法时立即传给外部文件;传递1选择行缓冲(仅在文本模式下可用),并且>1的整数以指示固定大小的块缓冲区的大小(以字节为单位)。buffering 的默认工作方式为:
1).二进制文件以固定大小的块进行缓冲,缓冲区的长度通常为4096或8192字节。
2). “交互式”文本文件使用行缓冲,其他文本文件使用固定块缓冲。

encoding 是用于解码或编码文件的编码的名称,仅适用于文本模式。默认编码为平台的编码,也支持其他的编码方法。参见Python codecs模块.

errors 可选字符串参数,指定如何处理编码和解码错误 (同样针对文本模式)。 这里不详细展开,可参见codecs错误处理方案

newline 控制通用换行模式如何生效(仅适用于文本模式)。它可以是 None' '' \n''\r''\r\n'

  • 输入时:如果newline = None,则采用通用换行模式。输入中的行可以以 '\n''\r''\r\n' 结尾,这些行都被翻译成 '\n'。如果newline = ’ ', 同样采用通用换行模式,但是行结尾将返回未翻译的字符给调用者。如果newline为任何其他的合法值,则输入行仅由给定字符串终止。
  • 输出时:如果 newline = None,则写入的任何换行字符都将转换为各个系统默认的行分隔符 os.linesep 。 如果newline = ' ' 或者' \n',则不进行翻译。如果 newline 是其他的合法值,则写入的任何换行字符将被转换为给定的字符串。

closefd :如果file为文件名,closefd 必须为True(默认值),否则会引发错误;如果file为文件描述符,设置closefd = False 可以使得底层文件描述符在文件关闭时仍然保持打开。

opener : 可以通过传递可调用的opener 来自定义开启器。通过使用参数调用opener获得文件对象的文件描述符。

1.2.2 文件的常见运算

读入名为 data 的文件并返回一个Python文件对象给,文件对象名为 input :

input = open('data','r')   #

将文件对象 input 读入进一个单一字符串:

aString = input.read()

将文件对象 input 开始N个字节之后的数据读入进一个单一字符串:

aString = input.read(N)

读取文件对象input的下一行到一个字符串:

aString = input.readline()

读取整个文件对象到字符串列表:

aList = input.readlines()

打开文件data,创建输出文件对象output:

output = open('data','w')

写入字节字符串到文件:

output.write(aString)

把列表里所有的字符串写入文件:

output.writelines(aList)

手动关闭文件:

output.close()

把输出缓冲区刷到硬盘中,但不关闭文件

output.flush()

文件迭代器读取文件:

for line in inpput :use line

1.2.3 使用文件的注意

  文件迭代器是最好的读取行的工具,它可以自动地在for循环、列表解析或其他迭代语句中对文件进行逐行读取。从文件读取的数据是一个字符串,如果需要其他类型的Python对象,可以用转换函数对其进行转换。同样,写入数据到文件的时候,Python也不会将对象自动转换为字符串,需要格式化了的字符串。

  调用文件的close方法会终止对外部文件的连接。当文件对象被回收的试试,Python也会自动关闭文件。但是建议手动进行close方法的调用,确保文件的关闭。

  默认情况下,文件的输出都是缓冲的,这表示写入的文本可能不会立刻从内存转到硬盘,我们可以关闭文件或者运行文件对象的flush方法,是的缓存的数据进入硬盘。

readline调用返回一个空字符串的时候表明到达文件的底部,文件的空行在调用readline后返回\n

2. 文件使用实例

2.1 open函数存储文件

 下面我们看一个存储文件的例子:

x, y, z = 7, 8 ,9
s = 'python'
l = [1, 2, 3]
d = dict(a = 'python', b = 'C++')

##以写入模式读入文件data.txt
f = open('data.txt','w')
f.write( s + '\n' )
f.write('%s, %s, %s\n'%(x,y,z))
f.write(str(l) + '&' + str(d) + '\n')
f.close()

回到VS Code的工作目录下,我们可以看到生成了一个data.txt的文件:
data.txt我们接着对data.txt进行操作,主要是进行对文件的行的操作:

#coding=utf-8
##打开data.txt文件
f = open('data.txt')

##读取文件对象f中第一行
line1 = f.readline()
##去除末尾的换行符号
line1 = line1.rstrip()
print("line1 is: ", line1)

##读取文件对象f中第二行
line2 = f.readline()
print("line2 is: ", line2)
##分割line2并返回一个列表
line2 = line2.split(',')
print("the new line2 is:", line2)
##转换字符串为整数
numbers = [int(s) for s in line2]
print("the sum of the numbers is:", sum(numbers))

##读取文件对象f中第三行
line3 = f.readline()
print("line3 is: ", line3)
##分割line3中的列表和字典
parts = line3.split('&')
print ("parts are:", parts)
##将字符串转换为各自的对象
objects = [ eval(p) for p in parts]
print('the first object is:',objects[0])
print('the second object is: ',objects[1])

运行结果为:

line1 is:  python
line2 is:  7, 8, 9

the new line2 is: ['7', ' 8', ' 9\n']
the sum of the numbers is: 24
line3 is:  [1, 2, 3]&{'a': 'python', 'b': 'C++'}

parts are: ['[1, 2, 3]', "{'a': 'python', 'b': 'C++'}\n"]
the first object is: [1, 2, 3]
the second object is:  {'a': 'python', 'b': 'C++'}

因为line1删除了行末尾的换行字符,因此前两个输出中间并没有空行,而line2未删除,因此在line2下方有一个空行。

2.2 pickle模块存储Python原生对象

pickle模块能够直接在文件中存储几乎任何Python对象的工具,不需要我们在其他对象和字符串之间转换,它是一个高级的通用的数据格式化和解析工具。模块 pickle实现了对一个Python对象结构的二进制序列化和反序列化。 “Pickling” 是将Python对象及其所拥有的层次结构转化为一个字节流的过程,而 “unpickling” 则相反,会将字节流转化回一个对象层次结构。
 我们主要通过pickle.dump(obj,file, protocol=None, *, fix_imports=True)来存储python对象到文件;通过pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")将后缀为.pkl的 pickle文件读取出来。

pickle.dump( obj, file, protocol=None, * , fix_imports=True)

obj 表示需要存储的Python对象
flie 表示需要存储Python对象的文件,必须保持打开
protocol 可选参数,整数(’0 - pickle.HIGHEST_PROTOCOL),如果为负数,默认选择支持的最高版本,protocol 表示协议版本,python3中默认为3,而且使用二进制模式来打开存储数据的文件,版本越高读取该文件所需的Python版本也越高,
fix_imports , 如果 fix_import = True, 并且protocol<3,pickle 将会映射Python3中的新名字到Python2去,使得pickle文件流在Python2中也可读

##载入pickle模块
import pickle
d = dict(name = 'Jack', age = 18, gender = 'male')
##以输出二进制的方式打开文件
f = open('dict.pkl','wb')
pickle.dump(d, f)
##注意关闭文件
f.close()

这样我们就存储好了一个名为dict.pkl的文件,下面我们尝试打开它:

pickle.load( file, * , fix_imports=True, encoding="ASCII", errors="strict")

因为pickle的协议版本会自动检测,因此不再需要参数protocol
flie 表示需要打开的.pkl文件,必须保持打开,而且有read()和readline()方法
fix_imports 表示映射Python2中的名字到Python3去
encoding errors 表明如何将Python2存储的.pkl8字节字符串实例解码为字节对象

import pickle

##以二进制文本方式打开文件
f = open('dict.pkl','rb')

##从文件中载入数据

MyObject = pickle.load(f)
print("The type of the loaded object is :",type(MyObject))
print("The loaded object is :",MyObject)

运行结果为:

The type of the loaded object is : <class 'dict'>
The loaded object is : {'name': 'Jack', 'age': 18, 'gender': 'male'}

通过pickle 模块,我们没有经过一系列类型转换就实现了Python对象的存取。pickle 模块其实执行的是对象序列化,直接将Python对象转换为字节字符串。我们可以看一下具体的情况。

import pickle

##以二进制文本方式打开文件
f = open('dict.pkl','rb')

##直接打印pickle文件
print('The object in pickle is :',f.read())

运行结果为:

The object in pickle is : b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00Jackq\x02X\x03\x00\x00\x00ageq\x03K\x12X\x06\x00\x00\x00genderq\x04X\x04\x00\x00\x00maleq\x05u.'

2.3 用struct模块存储和解析打包的二进制数据

 在一些高级应用中,我们需要处理打包的二进制数据,这些数据可能是其他语言的程序生成的,Python的struct模块能够构造并解析打包的二进制数据,将文件的字符串解读为二进制数据。
 我们通过struct.pack()函数生成一个打包的二进制文件:

struct.pack( format, value1, value2,...)
该函数返回一个 bytes 对象,其中包含根据格式字符串 *format* 打包的值 * value1 value2* ... 参数个数必须与格式字符串所要求的值完全匹配。

关于格式字符串:格式字符串是用来在打包和解包数据时指定预期布局的机制。 它们使用指定被打包/解包数据类型的 格式字符 进行构建。 还包括一些控制 字节顺序、大小和对齐方式的特殊字符。具体的请参见Python struct模块

下面看一个例子:

import struct

##以二进制写入模式打开data.bin的二进制文件
f = open('data.bin','wb')

##将数据返回为二进制数据
data = struct.pack('>i4sh', 7, b'good', 9)

print('The data is :', data)

##存储二进制数据
f.write(data)
f.close()

这时候已经生成了一个名为data.bin 的文件,运行结果为:

The data is : b'\x00\x00\x00\x07good\x00\t'

 上述程序中,’ > ‘ 指示打包数据的字节顺序为从大到小,i代表4字节整数,对应7;4s代表4字节字符串,对应 ‘good’ ;h 代表2字节short类型整数,对应8。

 我们通过 struct.unpack() 函数解析一个打包的二进制文件:

struct.unpack( format, buffer)

根据格式字符串 format 从缓冲区 buffer 解包,注意缓冲区buffer的字节大小必须匹配格式所要求的大小其返回结果为一个元组。

我们接着刚才的文件进行解析:

import struct

##以二进制读入模式打开data.bin的二进制文件
f = open('data.bin','rb')

##将文件读取在一个字符串中,这个字符串作为buffer
aString = f.read()

print("The string is: ", aString)
##解包二进制文件
values = struct.unpack('>i4sh',aString)

##显示解析结果
print('The results are: ', values)

运行结果为:

The string is:  b'\x00\x00\x00\x07good\x00\t'
The results are:  (7, b'good', 9)

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值