Python 08-文件读写
参考:Python 中的文件|极客教程 (geek-docs.com)
介绍
本文介绍 Python 如何处理文件以及标准输入和输出,我们将展示如何从文件读取和写入文件。
Python 中的所有内容都是一个对象,UNIX 中的所有内容都是文件。
磁盘文件
open
函数
内置函数,属于IO模块。open()返回一个file对象,该对象的类型取决于模式,并通过该对象执行标准文件操作。
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
-
file
是要打开的文件的名称。 -
mode
是一个可选字符串,指定打开文件的模式。它默认为“r”,表示以文本模式打开阅读。
模式 | 含义 |
---|---|
'r' | 读取(默认) |
'w' | 写入 |
'X' | 创建一个新文件并打开它进行写入 |
'a' | 追加 |
'b' | 二进制数据 |
‘t’ | 文本模式(默认) |
'+' | 打开磁盘文件进行更新(读写) |
-
buffering
是用于设置缓冲策略的可选整数。 -
encoding
是用于解码或编码文件的编码名称,默认是平台的编码 -
errors
是一个可选的字符串,它指定如何处理编码和解码错误。 -
newline
控制换行符的行为 : None, ‘’, ‘\n’, ‘\r’, 和 ‘\r\n’. -
closefd
为False,则在关闭文件时,底层文件描述符将保持打开状态。当给定文件名时,这不起作用,在这种情况下必须为True。 -
通过将可调用函数传递为opener,可以使用自定义的opener。然后用(file,flags)调用opener获得文件对象的底层文件描述符opener必须返回一个打开的文件描述符(将os.open作为opener传递会导致类似于传递None的功能)。
在文本模式下读取时,默认会把平台特定的行结束符 (Unix 上的
\n
, Windows 上的\r\n
) 转换为\n
。在文本模式下写入时,默认会把出现的\n
转换回平台特定的结束符。这样在幕后修改文件数据对文本文件来说没有问题,但是会破坏二进制数据例如JPEG
或EXE
文件中的数据。请一定要注意在读写此类文件时应使用二进制模式。
也可以使用字符串或bytearray作为文件进行读写。对于字符串,StringIO可以像在文本模式下打开的文件一样使用,对于字节,BytesIO可以像在二进制模式下打开的文件一样使用。
# 默认编码
>>> f = open("openpyxl 01 安装.md")
>>> f
<_io.TextIOWrapper name='openpyxl 01 安装.md' mode='r' encoding='cp936'>
# 指定编码
>>> f = open("openpyxl 01 安装.md",encoding="utf8")
>>> f
<_io.TextIOWrapper name='openpyxl 01 安装.md' mode='r' encoding='utf8'>
with 语句
在处理文件对象时,最好使用 with
关键字。
- 优点是当子句体结束后文件会正确关闭,即使在某个时刻引发了异常。
- 使用
with
相比等效的try
-finally
代码块要简短得多,处理文件通常会导致错误; - with语句通过封装通用的准备和清除任务来简化异常处理。
with open('workfile') as f:
read_data = f.read()
文件读取函数
-
read(n=-1)函数
从文件中读取指定数量的字节。 如果未指定字节数,它将读取整个文件。>>> with open('hello.txt', 'r') as f: ... f.read(3) ... f.read() ... 'hel' 'lo world\n你好,中国'
-
readline()方法
从文件读取一行。 字符串中保留尾随换行符。 函数到达文件末尾时,将返回一个空字符串。>>> with open('hello.txt', 'r') as f: ... f.readline() ... f.readline() ... 'hello world\n' '你好,中国'
-
readlines()方法
读取数据,直到文件结尾,然后返回行列表。>>> with open('hello.txt', 'r') as f: ... content = f.readlines() # 返回行列表,每行包含换行符 ... >>> for x in content: ... print(x.strip()) # 打印每行,用str.strip() 去除空白字符,包括换行 ... hello world 你好,中国
-
num = write()方法
将字符串写入文件, 返回字节数>>> with open('hello.txt', 'w') as f: ... f.write("hello world\n") # 12 ... f.write("你好,中国") # 5 ... 12 5
文件位置
文件位置是我们从中读取数据的文件位置。
-
tell()
方法给出文件中的当前位置>>> with open('hello.txt', 'r') as f: ... f.read(5) # 读5个字符 ... f.tell() # 当前位置为5 ... 'hello' 5
-
seek(offset, whence=0, /)
方法移动文件中的位置。
whence
选项:* 0 -- 流始端(默认值);偏移量应为零或正 * 1 -- 当前流位置;偏移量可能为负 * 2 -- 流末端;偏移量通常为负
>>> with open('hello.txt', 'r') as f: ... f.read(5) ... f.tell() ... f.seek(10) ... f.read() ... 'hello' 5 10 'd\n你好,中国'
标准 I/O
基本的 I/O 连接共有三种:标准输入,标准输出和标准错误。
Python 中的标准输入和输出是sys
模块中的对象。
对象 | 描述 |
---|---|
sys.stdin | 标准输入是进入程序的数据。 标准输入来自键盘。 |
sys.stdout | 标准输出是我们使用 print 关键字打印数据的地方。 |
sys.stderr | 标准错误是程序写入错误消息的流。 通常是文本终端。 |
符合 UNIX 的哲学,标准 I/O 流 是 文件对象。
标准输入
stdin 用于所有交互式输入(包括对 input() 的调用);
import sys
print('Enter your name: ', end='')
name = ''
sys.stdout.flush()
while True:
c = sys.stdin.read(1)
if c == '\n':
break
name = name + c
print('Your name is:', name)
但是,通常为了获得输入,使用更高级别的函数:input() 。
>>> data = input("What's your name ? ")
What's your name ? Peter
>>> print(f"Welcom {data}")
Welcom Peter
>>> print(f"Welcom {data:^10}")
Welcom Peter
标准输出
- stdout 用于 print() 和 expression 语句的输出,以及用于 input() 的提示符;
>>> import sys
>>> sys.stdout.write('Honore de Balzac, Father Goriot\n')
Honore de Balzac, Father Goriot
32
-
通常使用print函数
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
-
默认情况下,
print
函数将文本输出到sys.stdout
。print('Honore de Balzac') print('The Splendors and Miseries of Courtesans', 'Gobseck', 'Father Goriot', sep=":") vals = [1, 2, 3, 4, 5] for e in vals: print(e, end=' ') print()
-
print()
函数包含一个file
参数,该参数告诉我们在哪里打印数据。所以可以使用print()
函数写入文件。with open('works.txt', 'w') as f: print('Beatrix', file=f) print('Honorine', file=f) print('The firm of Nucingen', file=f)
-
标准错误输出和标准错误差不多,都是数据的流出对象,略。
标准IO的重定向和恢复
标准输出可以重定向。 在以下示例中,我们将标准输出重定向到常规文件。
- 脚本中,我们将标准输出重定向到常规文件
output.txt
。 - 然后,恢复原始的标准输出。
std.output
的原始值保存在特殊的sys.__stdout__
变量中。
import sys
with open('output.txt', 'w') as f:
sys.stdout = f
print('Lucien')
sys.stdout.write('Rastignac\n')
sys.stdout.writelines(['Camusot\n', 'Collin\n'])
sys.stdout = sys.__stdout__
print('Bianchon')
sys.stdout.write('Lambert\n')
对象的序列化和反序列化
模块 pickle 实现了对一个 Python 对象结构的二进制序列化和反序列化。
- “pickling” 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程,
- “unpickling” 是相反的操作,会将(来自一个 binary file 或者 bytes-like object 的)字节流转化回一个对象层次结构。
pickling(和 unpickling)也被称为“序列化”, “编组” 或者 “平面化”。为避免混乱,采用术语 “封存 (pickling)” 和 “解封 (unpickling)”。
注解
序列化是一种比持久化更底层的概念,虽然
pickle
读取和写入的是文件对象,但它不处理持久对象的命名问题,也不处理对持久对象的并发访问(甚至更复杂)的问题。pickle
模块可以将复杂对象转换为字节流,也可以将字节流转换为具有相同内部结构的对象。处理这些字节流最常见的做法是将它们写入文件,但它们也可以通过网络发送或存储在数据库中。shelve
模块提供了一个简单的接口,用于在 DBM 类型的数据库文件上封存和解封对象。pickle : 有泡菜、腌渍的意思
pickling:就解释成酸洗、腌渍
unpickling:解释成解腌
方法
-
使用dump()方法腌制对象。
dump(object, file) dumps(object) -> string
-
使用load()方法解开对象。
load(file) -> object loads(string) -> object
实例
#!/usr/bin/env python
# pickle_ex.py
import pickle
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self):
return self.name
def get_age(self):
return self.age
person = Person('Monica', 15)
print(person.get_name())
print(person.get_age())
with open('monica', 'wb') as f:
pickle.dump(person, f)
with open('monica', 'rb') as f2:
monica = pickle.load(f2)
print(monica.get_name())
print(monica.get_age())