IO: 输入与输出
2025-02-17
- 程序要能够运行,需要与外界进行通信,需要与用户交互,读写文件,访问网页等。这些,我们通常称之为输入和输出(简称 I/O)
- 基本的控制台I/O,包括打印消息,使用函数input读取用户输入的字符串
- 主要介绍一些设置字符串格式的方法,能够通过控制台I/O输出美观的字符串
读写文件
- 文件I/O,即读写文件
- 主要介绍使用文本文件,二进制文件以及功能强大的pickle模块
设置字符串格式
- 主要有 较老的字符串插入
- 新的格式字符串
字符串插入
- 字符串 插入是一种设置字符串格式的简单方法
# 案例:如何控制小数位数 用 f 表示浮点数 前面加上数字表示的是: 留小数点后的几位数
x = 1/81
print(x)
print('value: %.2f' % x)
print('value: %.5f' % x)转换说明符
| 说明符 | 含义 |
|---|---|
| d | 整数 |
| o | 八进制(基数为8的)值 |
| x | 小写十六进制(基数为16的)数 |
| X | 大写十六进制(基数为16的)数 |
| e | 小写科学记数法表示的浮点数 |
| E | 大写科学记数法表示的浮点数 |
| F | 浮点数 |
| s | 字符串 |
| % | %字符 |
x
print('x = %f' % x)
print('x = %e' % x)
print('x = %E' % x)
a , b, c = 'cat', 3.14, 6
s = 'There\'s %d %ss older than %.2f years' % (c,a,b)格式字符串
创建美观字符串的方式是结合使用格式字符串和字符串函数 format(value,format_spec)
模块包
在字符串插入和格式字符串都不够强大或灵活时,可能需要使用模块包
如:Cheetah 或 Django 提供的模块包
在需要创建大量动态生成的网页是,上面的模块包很有用
# format 案例
ss = 'My {pet} has {prob}'.format(pet = 'dog',prob = 'fleas')
# 按位置替换值
sss = 'My {0} has {1}'.format('dog','fleas')
# 像字符串插入 转换说明符
a1 = '1/18 = {x}'.format(x=1/18)
a2 = '1/18 = {x:f}'.format(x=1/18)
a3 = '1/18 = {x:.3f}'.format(x=1/18)
# 指定格式设置参数
a4 = 'num = {x:.{d}f}'.format(x=1/81,d=3)
a5 = 'num = {x:.{d}f}'.format(x=1/80,d=4)读写文件
文件是一个命令的比特集合,存储在硬盘,U盘,闪存条等辅助存储设备中
文件有: 二进制文件 文本文件
本质上是 存储在磁盘中的字符串
文本文件具有如下特点:
- 基本上是磁盘中的字符串。python源代码文件和HTML文件都属于文本文件
- 可使用任何文本编辑器进行编辑
- 每种文本文件都需要使用相应的分析程序(parser)来阅读。
- 通常比等价的二进制文件大。需要通过网络发送大型文本文件时,这是一个问题
二进制文件具有如下特点
- 通常是人类无法阅读,使用常规文本编辑器无法查看,需要使用特殊查看器显示其内容
- 占据的空间比等价的文本文件小
如果要在python字符串中包含'' 必须使用'\' 才可以
- 'c:\home\tjd\Desktop\python'
- 想避免使用两个放斜杠,可以使用原始字符串
- r'c:\home\tjd\Desktop\python'
检查文件和文件夹
- 使用os.listdir(os.getcwd())查看当前的工作目录或者文件夹
| 函数名 | 作用 |
|---|---|
| os.getcwd() | 返回当前工作目录的名称 |
| os.listdir(p) | 返回一个字符串列表,其中包含路径P指定的文件夹和所有文件和文件夹的名称 |
| os.chdir(p) | 将当前工作目录设置为路径p |
| os.path.isfile(p) | 当路径p指定的是一个文件的名称时,返回True,否则返回False # 布尔值判断 |
| os.path.isdir(p) | 当路径p制定的是一个文件夹的名称是,返回True, 否则返回False # 布尔值判断 |
| os.stat(fname) | 返回有关fname的信息。如大小 和 最后一次修改的时间 |
# 获取当前目录路径
def list_cwd():
return os.listdir(os.getcwd())
# 下面的两个相关的辅助函数,使用列表解析分别返回当前工作目录中的文件
def files_cwd():
return [p for p in list_cwd() if os.path.isfile(p)]
def folders_cwd():
return [p for p in list_cwd() if os.path.isdir(p)]
# 只想获取当前工作目录中的.py文件
def list_py(path = None):
if path == None:
path = os.getcwd()
return [fname for fname in os.listdir(path) if os.path.isfile(fname) if fname.endswith('.py')]
def cwd_size_in_bytes2():
return sum(size_in_bytes(s) for f in files_cwd())
# 返回当前工作目录中所有文件的大小总和
def size_in_bytes(fname):
return os.stat(fname).st_size
def cwd_size_in_bytes():
total = 0
for name in files_cwd():
total += size_in_bytes(name)
return total处理文本文件
- 在python中处理文本文件相对容易
- 打开文件 ----> 处理文件 ------> 关闭文件
逐行读取文本文件
读取文本文件的最常见方式可能是每次读取一行。
python文件打开模式
字符 含义 'r' 只读模式(默认) 'w' 写入模式 'a' 在文件末尾附加 'b' 二进制模式 't' 文本模式(默认模式) '+' 为读写打开文件 如果只想读取文本文件,可在调用函数open时值只传递文件名: 比如: f = open(filename)
如果为指定模式,python默认为只读模式
# 逐行读取文件
def print_file(fname):
with open(fname, 'r') as f: # 使用with语句自动关闭文件
for line in f:
print(line, end='') # 设置end=''以避免额外的空行将整个文本文件作为一个字符串进行获取
- 另一种读取文本文件的最常见方式是: 将其作为一个大型字符串进行读取
- 下面的案例中,函数比 print_file 短小,简单。
- 但如果文件很大,将占用大量内存。导致 降低计算机的运行速度
# 案例
def print_file2(fname):
f = open(fname,'r')
print(f.read())
f.close()
# 改进
def print_file2(fname):
print(open(fname,'r').read())写入文本文件
- 写入文本文件只比读取文本文件复杂一些
# 案例
def make_story1():
f = open('story.txt','w')
f.write('Marh hand a little lamb,\n')
f.write('and then she some more,\n')
f.close()
return None
# 将文本写入文件需要调用 f.write(),并将要写入的字符串传递给它。字符串将以指定的顺序写入文件
# 当story.txt 存在,调用open('story.txt','w') 将删除原有文件
# 案例改进
import os
def make_story2():
if os.path.isfile('story.txt'):
print('story.txt already exists')
else:
open('story.txt','w').write('Many had a little lamb,\n and then she had some more.\n')附加到文件文件末尾
- 附加的这种模式是不会删除文件既有的内容,也就是不会删除文件
# 案例
def add_to_story(line,fname = 'story.txt'):
# 使用 'a' 模式打开文件,准备在文件末尾追加内容
with open(fname, 'a') as f:
# 将内容追加到文件末尾
f.write(line)将字符串插入到文件开头
- 将字符串插入到文件的开头,由于操作系统没有为这样提供直接支持,要将文本插入到文件开头,最简单的额方式是:
- 将文件读取到一个字符串中,将新文本插入到该字符串,再将这个字符串写入原来的文件
# 案例
def insert_title(title,fname = 'story.txt'):
# 使用 'r+' 模式打开文件,准备读取和写入文件
with open(fname, 'r+') as f:
# 读取整个文件到字符串变量 temp 中
temp = f.read()
# 在字符串变量 temp 的开头插入标题(title)
temp = title + '\n\n' + temp
# 将文件指针重新指向开头
f.seek(0)
# 将修改后的字符串写入文件
f.write(temp)处理二进制文件
如果文件不是文本文件,将被视为二进制文件
二进制文件是以模式'b'打开,可访问其各个字节
def is_gif(fname): # 使用 'br' 模式打开文件,准备读取二进制数据 with open(fname, 'br') as f: # 读取文件的前4个字节 first4 = tuple(f.read(4)) # 检查是否为GIF图像文件的标志 return first4 == (0x47, 0x49, 0x46, 0x38)上面的函数是检查fname是不是GIF图像文件。
方法是检查其前4个字节是不是(0x47, 0x49, 0x46, 0x38)
所有GIF图像文件都以这4个字节开头
在python,类似与0x47是十六进制数,十六进制适合用于处理字节,每个十六进制位对应4个比特,两个十六进制位(0x47)可描述一个字节
文件的模式是以'br'打开,表示二进制读取模式
调用f.read(n) 来读取接下来的n个字节。
与文本文件对象一样,二进制文件对象也使用文件指针来记录接下来应读取的那个字节
pickle
- Python模块pickle执行的操作通常被称为对象串行化(简称串行化),其基本思想是将复杂的数据结构转换为字节流,即创建数据结构的串行化表示。
- 在处理二进制文件方面,通常会使用pickle这个模块,除了数据结构外,还可以用它来存储函数。
- 重要注意:pickle不能用于读写特殊格式的二进制文件,如GIF文件,这种文件只能逐字节处理。
# pickle 模块案例
import pickle
def make_pickled_file():
# 定义一个字典,用于存储姓名和分数
grade = {
'alan': [4, 8, 10, 10],
'tom': [7, 7, 7, 8],
'dan': [5, 6, 9, None],
'may': [10, 8, 10, 8]
}
# 使用 'wb' 模式打开文件,准备写入二进制数据
with open('grades.date', 'wb') as outfile:
# 使用 pickle.dump() 将数据结构存储到磁盘
pickle.dump(grade, outfile)
def get_pickles_data():
# 使用 'rb' 模式打开文件,准备读取二进制数据
with open('grades.date', 'rb') as infile:
# 使用 pickle.load() 从磁盘获取数据结构
grades = pickle.load(infile)
return gradesshelve 模块
- 提供了一个简单的持久化存储方式,可以将Python对象存储到一个文件中,并在需要时从文件中读取出来。
- shelve 模块使用了dbm模块来存储数据,dbm模块提供了一个简单的键值对存储方式。
- shelve 模块的优点是可以直接存储Python对象,不需要进行序列化和反序列化操作,非常方便。
import shelve
# 创建一个shelve对象
with shelve.open('example.shelve') as shelf:
# 存储数据
shelf['data'] = {'name': 'example', 'version': '1.0'}
# 检索数据
data = shelf['data']
print(data)sqlite3 模块
- sqlite3 模块提供了一个轻量级的数据库引擎,可以直接访问SQLite数据库。
- 它允许你编写SQL命令来查询和检索数据,还可以执行事务和管理数据库连接。
import sqlite3
# 连接到数据库,如果数据库不存在,则会创建一个新的数据库
conn = sqlite3.connect('example.db')
# 创建一个游标对象
cursor = conn.cursor()
# 创建表
cursor.execute('''CREATE TABLE IF NOT EXISTS users
(id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL)''')
# 插入数据
cursor.execute("INSERT INTO users (name,email) VALUES ('John Doe','john.doe@example.com')")
# 保存更改
conn.commit()
# 查询数据
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
for row in rows:
print(row)
# 关闭连接
conn.close()读取网页
- Python访问网络的常见任务是自动读取网页内容
- 可以使用urllib模块或webbrowser模块
urllib模块
- 使用urllib.request.urlopen()打开网页
- 使用read()方法读取网页内容
- 打印网页内容的前25个字符
import urllib.request
# 读取 www.example.tk 网页案例
with urllib.request.urlopen('https://www.example.tk') as page:
html = page.read()
print(html[:25])webbrowser模块
- 使用webbrowser.open()函数直接在浏览器中显示网页
- 注意:webbrowser.open()函数会直接打开浏览器显示网页,而不是返回网页内容
- 如果需要读取网页内容,需要使用urllib.request.urlopen()或其他方法
import webbrowser
# 使用webbrowser模块打开网页
webbrowser.open('http://www.yahoo.com')
# 注意:webbrowser.open()函数会直接打开浏览器显示网页,而不是返回网页内容
# 如果需要读取网页内容,需要使用urllib.request.urlopen()或其他方法