用 `with` 打开文件
变量在程序结束时消失,文件不会。open(path, mode) 返回一个文件对象,mode 说明你要做什么:"r" 读取(默认)、"w" 写入、"a" 追加。始终用 with 块打开文件:with open(path) as file:。块结束时,Python 会替你关闭文件,即使里面出了错,这样数据不会丢失,也不会只写一半。传入 encoding="utf-8",让文本在任何电脑上以相同方式读写。
# Write a file, then read it back
with open("fills.txt", "w", encoding="utf-8") as file:
file.write("AAPL,184.25,200\n")
file.write("MSFT,410.20,50\n")
with open("fills.txt", encoding="utf-8") as file:
text = file.read()
print(repr(text)) # 'AAPL,184.25,200\nMSFT,410.20,50\n'逐行读取
file.read() 把整个文件作为一个字符串返回。更常见的做法是直接遍历文件对象,它每次给出一行,对于内存装不下的大文件也适用:for line in file:。每一行末尾仍带有 \n,所以用 line.strip() 清理。空行清理后变成空字符串 "",它为假,所以 if text: 会跳过它。需要一次拿到所有行时,可用 file.readlines() 和 text.splitlines(),它们返回行的列表。
# Read line by line, skipping blank lines
with open("fills.txt", "a", encoding="utf-8") as file:
file.write("\n") # a blank line
total = 0.0
with open("fills.txt", encoding="utf-8") as file:
for line in file:
text = line.strip()
if not text:
continue
symbol, price, quantity = text.split(",")
total += float(price) * int(quantity)
print(round(total, 2)) # 57360.0写入与追加
file.write(text) 原样写入你给的字符串,并返回字符数。它不会自动加换行,所以每行末尾要自己加 "\n"。模式 "w" 会先清空文件(不存在则创建),因此用 "w" 打开已有文件会丢掉原来的内容。模式 "a" 保留原有内容并在末尾追加。只能写入字符串:先转换数字,例如用 f"{price:.2f}" 这样的 f-string。
# "w" starts over, "a" adds to the end
with open("log.txt", "w", encoding="utf-8") as file:
file.write("start\n")
with open("log.txt", "a", encoding="utf-8") as file:
file.write("order 1 filled\n")
file.write(f"pnl {12.5:+.2f}\n")
with open("log.txt", encoding="utf-8") as file:
print(file.read().splitlines()) # ['start', 'order 1 filled', 'pnl +12.50']
with open("log.txt", "w", encoding="utf-8") as file:
pass # opening with "w" emptied it
with open("log.txt", encoding="utf-8") as file:
print(repr(file.read())) # ''路径与缺失的文件
像 "fills.txt" 这样的相对路径会在程序的当前文件夹中查找;用 os.path.join(folder, name) 构建路径,就不必操心分隔符。以读取方式打开不存在的文件会引发 FileNotFoundError,当文件不存在是预料之中的情况时,可用 try/except 捕获。对于小文件,pathlib.Path(path).read_text() 和 .write_text(text) 一次调用就完成打开、读写和关闭。
import os
from pathlib import Path
# A missing file is an exception you can handle
def count_lines(path):
try:
with open(path, encoding="utf-8") as file:
return len(file.read().splitlines())
except FileNotFoundError:
return 0
print(count_lines("fills.txt")) # 3
print(count_lines("nope.txt")) # 0
# pathlib does open + read + close in one call
path = Path(os.path.join(".", "fills.txt"))
print(path.read_text(encoding="utf-8").splitlines()[0]) # AAPL,184.25,200"w" 会毁掉数据,且无法撤销。先约定一个简单的格式(每行一条记录,字段用逗号分隔),并同时编写读取和写入代码,使二者保持一致。接下来你会学到 CSV 格式,它正是把这个想法规范化。with open(path, mode, encoding="utf-8") as file:打开文件并确保关闭。for line in file:每次读一行;line.strip()去掉换行符。"w"会清空文件,"a"追加;write不会加换行。
下一节:CSV 文件,存储价格和成交表格的标准方式。
实验:评分内容
- 用
read_symbols从文件加载自选股列表25 分 - 用
parse_trades把成交文件转换为元组25 分 - 用
write_report保存盈亏报告25 分 - 用
append_lines向日志追加内容而不丢失原有内容25 分