Python 3 - 文件 I/O
Python 3 - 文件输入/输出 (I/O)
Section titled “Python 3 - 文件输入/输出 (I/O)”本章涵盖了在 Python 3 中读写文件的基本函数和技术。
打印到屏幕 (标准输出)
Section titled “打印到屏幕 (标准输出)”print() 函数是将输出显示到标准输出流(通常是你的终端/控制台)的主要方式。
#!/usr/bin/env python3
print("Hello, world!")
name = "Alice"age = 30print("Name:", name, "Age:", age) # 默认情况下多个参数用空格分隔print(f"Name: {name}, Age: {age}") # 使用 f-string 进行格式化输出
print("No newline at the end ->", end="") # 使用 'end' 参数改变结束符print("<- See?")print("Item1", "Item2", sep=" | ") # 使用 'sep' 参数改变分隔符输出:
Hello, world!Name: Alice Age: 30Name: Alice, Age: 30No newline at the end -><- See?Item1 | Item2读取键盘输入 (标准输入)
Section titled “读取键盘输入 (标准输入)”input() 函数从标准输入(键盘)读取用户输入的一行文本,并将其作为字符串返回。
注意:Python 2 有 raw_input()(返回字符串)和 input()(尝试将输入评估为 Python 代码)。在 Python 3 中,input() 的行为类似于 Python 2 的 raw_input(),总是返回一个字符串。如果你需要其他类型(例如数字),必须明确进行类型转换。
#!/usr/bin/env python3
user_name = input("Enter your name: ")print(f"Hello, {user_name}!")
age_str = input("Enter your age: ")# 输入始终是字符串,如果需要其他类型必须进行转换try: age_num = int(age_str) print(f"Next year, you will be {age_num + 1}.")except ValueError: print("Invalid age entered. Please enter a number.")Python 提供了强大的工具用于与文件系统上的文件进行交互。
打开文件:open() 函数和 with 语句(推荐)
Section titled “打开文件:open() 函数和 with 语句(推荐)”在读写文件之前,你必须使用内置的 open() 函数打开文件。它会返回一个文件对象。
最佳实践: 在操作文件时使用 with 语句。它能确保即使在处理过程中发生错误,文件也会自动关闭。
语法 (with 语句)
Section titled “语法 (with 语句)”with open(file_path, mode='r', encoding=None) as file_variable: # 操作文件对象 (file_variable) pass# 文件在此处自动关闭open() 的参数:
file_path: 一个字符串,包含文件的路径(例如,'my_data.txt','../config/settings.ini')。mode: 一个字符串,指示应如何打开文件(读取、写入、追加等)。默认为'r'(文本读取)。参见下表。encoding: 指定用于解码/编码文件的编码方式(例如,'utf-8','latin-1')。对于文本模式至关重要。如果为None,则使用系统默认编码,但通常推荐明确设置'utf-8'以保证可移植性。
常见文件模式
Section titled “常见文件模式”| 模式 | 描述 |
|---|---|
'r' | 读取(默认)。文本模式。如果文件不存在则报错。 |
'w' | 写入。文本模式。如果文件不存在则创建,如果存在则截断(清空)。 |
'a' | 追加。文本模式。如果文件不存在则创建。写入内容会添加到文件末尾。 |
'rb' | 二进制读取。用于非文本文件(图片、可执行文件)。 |
'wb' | 二进制写入。如果文件存在则截断。 |
'ab' | 二进制追加。 |
'r+' | 读写。文本模式。不截断。如果文件不存在则报错。 |
'w+' | 写读。文本模式。如果文件存在则截断。 |
'a+' | 追加并读。文本模式。写入到文件末尾。 |
'x' | 独占创建。文本模式。如果文件已存在则失败。 |
'xb', 'x+' 等 | 独占创建的二进制或读写变体。 |
注意:在模式后追加 b(例如,'rb','wb')表示二进制模式。如果未指定 b,则默认为文本模式(t)。
文件对象属性
Section titled “文件对象属性”文件打开后,文件对象具有有用的属性:
| 属性 | 描述 |
|---|---|
file.closed | 布尔值:如果文件已关闭则为 True,否则为 False。 |
file.mode | 字符串:打开文件时使用的模式(例如,'r','wb')。 |
file.name | 字符串:文件的名称/路径。 |
file.encoding | 字符串:使用的编码(在文本模式下)。 |
#!/usr/bin/env python3
try: with open("sample.txt", "w", encoding="utf-8") as f: print(f"File Name: {f.name}") print(f"Opening Mode: {f.mode}") print(f"Encoding: {f.encoding}") print(f"Is Closed? {f.closed}") f.write("Test line\n") print(f"After with block, Is Closed? {f.closed}")except IOError as e: print(f"Error opening/writing file: {e}")写入文件 (write, writelines)
Section titled “写入文件 (write, writelines)”使用 write() 方法将字符串(在文本模式下)或字节串(在二进制模式下)写入文件。它返回写入的字符数/字节数。在文本模式下,如果需要换行,请记得手动包含换行符 (\n)。
writelines() 方法将一个序列(例如,一个列表)的字符串写入文件。它不会在字符串之间添加换行符。
#!/usr/bin/env python3
lines_to_write = [ "First line.\n", "Second line.\n", "Third line without newline."]
try: with open("output.txt", "w", encoding="utf-8") as f: num_chars = f.write("This is a single line written with write().\n") print(f"Wrote {num_chars} characters.")
f.writelines(lines_to_write) print("Wrote multiple lines with writelines().")except IOError as e: print(f"Error writing to file: {e}")从文件读取 (read, readline, readlines, 迭代)
Section titled “从文件读取 (read, readline, readlines, 迭代)”有几种读取方法:
read([size]): 从文件中读取size个字符/字节。如果省略size或size为负数,则读取整个文件内容。readline(): 从文件中读取一行,包括末尾的换行符 (\n)。在文件末尾返回空字符串。readlines(): 读取文件中所有剩余的行,并将其作为字符串列表返回。- 迭代: Pythonic 的逐行读取文件的方式是直接迭代文件对象。
#!/usr/bin/env python3
# 假设 output.txt 文件在前面的例子中已经创建
try: # 方法 1: 读取整个文件 with open("output.txt", "r", encoding="utf-8") as f: content = f.read() print("--- Read All ---") print(content)
# 方法 2: 使用迭代逐行读取 (推荐) with open("output.txt", "r", encoding="utf-8") as f: print("--- Read by Iteration ---") for line in f: print(line, end='') # print 会添加换行符,所以使用 end='' 防止双重换行 print("\n-------------------------")
# 方法 3: Readlines 读取到列表 with open("output.txt", "r", encoding="utf-8") as f: lines_list = f.readlines() print("--- Readlines List ---") print(lines_list) # 列表中包含换行符
except FileNotFoundError: print("Error: output.txt not found.")except IOError as e: print(f"Error reading file: {e}")文件位置 (tell, seek)
Section titled “文件位置 (tell, seek)”tell(): 返回文件指针(光标)的当前位置,以从文件开头算起的字节数(整数)表示。
seek(offset, [whence]): 移动文件指针。offset 是要移动的字节数。whence 确定参考点:
0(默认):从文件开头算起(os.SEEK_SET)。1:相对于当前位置算起(os.SEEK_CUR)。2:相对于文件末尾算起(os.SEEK_END)。
注意:在文本模式下进行 seek(除了 seek(0))可能不可靠,除非你 seek 到之前由 tell() 返回的位置。二进制模式提供更可预测的按字节偏移量进行 seek。
#!/usr/bin/env python3
try: with open("output.txt", "r+", encoding="utf-8") as f: # r+ 模式允许读写 text = f.read(10) print(f"Read first 10 chars: '{text}'")
current_pos = f.tell() print(f"Current position: {current_pos}")
f.seek(0) # 返回文件开头 print(f"Position after seek(0): {f.tell()}")
f.seek(5, 1) # 从当前位置(即 0)向前移动 5 个字节 print(f"Position after seek(5, 1): {f.tell()}") print(f"Reading from new pos: '{f.readline().strip()}'")
# 从开头位置覆盖写入 f.seek(0) f.write("OVERWRITTEN!")
except FileNotFoundError: print("Error: output.txt not found.")except IOError as e: print(f"Error seeking/reading file: {e}")文件和目录管理 (os 和 pathlib)
Section titled “文件和目录管理 (os 和 pathlib)”Python 提供了模块用于与文件系统交互,而不仅仅是读写文件内容。
os模块: 传统的与操作系统交互的模块,包括文件操作。pathlib模块 (Python 3.4+): 一种现代化、面向对象的方式来处理文件系统路径和操作。通常因其清晰性和易用性而被优先使用。
我们将展示在适用的情况下使用这两个模块的例子。
重命名和删除文件
Section titled “重命名和删除文件”#!/usr/bin/env python3import osfrom pathlib import Path
# 创建一个临时文件with open("test_old.txt", "w") as f: f.write("temporary file")
# --- 使用 os 模块 ---try: os.rename("test_old.txt", "test_new_os.txt") print("Renamed using os") os.remove("test_new_os.txt") print("Removed using os")except OSError as e: print(f"OS Error: {e}")
# 为 pathlib 例子重新创建文件with open("test_old.txt", "w") as f: f.write("temporary file")
# --- 使用 pathlib 模块 ---try: old_path = Path("test_old.txt") new_path_pl = Path("test_new_pathlib.txt") old_path.rename(new_path_pl) print("Renamed using pathlib") new_path_pl.unlink() # pathlib 使用 unlink() 删除文件/符号链接 print("Removed using pathlib")except OSError as e: print(f"Pathlib Error: {e}")创建、改变、获取当前目录以及删除目录。
#!/usr/bin/env python3import osfrom pathlib import Path
# --- 使用 os 模块 ---new_dir_os = "my_temp_dir_os"try: print(f"Current directory (os): {os.getcwd()}") os.mkdir(new_dir_os) # 创建目录 print(f"Created directory: {new_dir_os}") os.chdir(new_dir_os) # 进入新目录 print(f"Current directory after chdir (os): {os.getcwd()}") os.chdir("..") # 返回上一级目录 print(f"Current directory after chdir .. (os): {os.getcwd()}") os.rmdir(new_dir_os) # 删除目录(必须为空) print(f"Removed directory: {new_dir_os}")except OSError as e: print(f"OS Error: {e}") # 如果中间出错,进行清理 if os.path.exists(new_dir_os): if os.path.basename(os.getcwd()) == new_dir_os: os.chdir("..") os.rmdir(new_dir_os)
print("\n---\n")
# --- 使用 pathlib 模块 ---new_dir_pl = Path("my_temp_dir_pl")try: print(f"Current directory (pathlib): {Path.cwd()}") new_dir_pl.mkdir() # 创建目录 print(f"Created directory: {new_dir_pl}") # pathlib 没有直接的 chdir 方法,使用 os.chdir() os.chdir(new_dir_pl) print(f"Current directory after chdir (pathlib): {Path.cwd()}") os.chdir("..") print(f"Current directory after chdir .. (pathlib): {Path.cwd()}") new_dir_pl.rmdir() # 删除目录(必须为空) print(f"Removed directory: {new_dir_pl}")except OSError as e: print(f"Pathlib Error: {e}") # 如果中间出错,进行清理 if new_dir_pl.exists(): if Path.cwd().name == new_dir_pl.name: os.chdir("..") new_dir_pl.rmdir()其他有用的函数/方法:
os.makedirs(path, exist_ok=False)/Path(path).mkdir(parents=True, exist_ok=False): 递归创建目录(包括中间目录)。os.path.exists(path)/Path(path).exists(): 检查路径是否存在。os.path.isfile(path)/Path(path).is_file(): 检查路径是否为常规文件。os.path.isdir(path)/Path(path).is_dir(): 检查路径是否为目录。os.listdir(path)/Path(path).iterdir(): 列出目录内容。