跳到主要内容

第8章:IO 操作

作为 Java 开发者,你已经熟悉了 Java 的 IO 操作。Python 的 IO 操作与 Java 有很多相似之处,但也有一些重要的区别。本章将详细对比两种语言的 IO 操作。

8.1 文件读写

Java 文件读写

// 读取文件
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}

// 写入文件
try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
writer.write("Hello, World!");
writer.newLine();
writer.write("Welcome to Java IO.");
} catch (IOException e) {
e.printStackTrace();
}

Python 文件读写

# 读取文件
with open("example.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.strip())

# 写入文件
with open("output.txt", "w", encoding="utf-8") as file:
file.write("Hello, World!\n")
file.write("Welcome to Python IO.\n")

对比

特性JavaPython
打开文件new FileReader()new FileWriter()open() 函数
资源管理try-with-resourceswith 语句
读取方式readLine()read()直接迭代文件对象或 read()
写入方式write()write()
异常处理必须捕获 IOException可以捕获 IOErrorFileNotFoundError
编码处理需要显式指定可以在 open() 中指定 encoding 参数

Python 文件操作示例

# 文件模式
# r: 只读(默认)
# w: 写入(覆盖)
# a: 追加
# x: 创建并写入
# b: 二进制模式
# t: 文本模式(默认)

# 读取整个文件
with open("example.txt", "r") as file:
content = file.read()
print(content)

# 读取指定字符数
with open("example.txt", "r") as file:
content = file.read(10) # 读取前10个字符
print(content)

# 读取所有行
with open("example.txt", "r") as file:
lines = file.readlines()
for line in lines:
print(line.strip())

# 二进制文件
with open("image.jpg", "rb") as file:
data = file.read()
print(f"File size: {len(data)} bytes")

# 追加写入
with open("output.txt", "a") as file:
file.write("This is an appended line.\n")

# 创建新文件
with open("new_file.txt", "x") as file:
file.write("This is a new file.\n")

8.2 标准输入输出

Java 标准输入输出

// 标准输出
System.out.println("Hello, World!");
System.out.print("Enter your name: ");

// 标准输入
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int age = scanner.nextInt();

System.out.println("Hello, " + name + ", you are " + age + " years old.");

Python 标准输入输出

# 标准输出
print("Hello, World!")
print("Enter your name: ", end="") # 不换行

# 标准输入
name = input("Enter your name: ")
age = int(input("Enter your age: "))

print(f"Hello, {name}, you are {age} years old.")

对比

操作JavaPython
标准输出System.out.println()print()
不换行输出System.out.print()print(..., end="")
标准输入Scannerinput() 函数
输入转换需要手动转换使用类型函数转换

8.3 序列化与反序列化

Java 序列化

// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.ser"))) {
Person person = new Person("Alice", 25);
oos.writeObject(person);
} catch (IOException e) {
e.printStackTrace();
}

// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.ser"))) {
Person person = (Person) ois.readObject();
System.out.println(person.getName() + ", " + person.getAge());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}

Python 序列化

import pickle

# 序列化
data = {"name": "Alice", "age": 25, "city": "New York"}
with open("data.pkl", "wb") as file:
pickle.dump(data, file)

# 反序列化
with open("data.pkl", "rb") as file:
loaded_data = pickle.load(file)
print(loaded_data)

# 使用 json 模块
import json

# 序列化
data = {"name": "Alice", "age": 25, "city": "New York"}
with open("data.json", "w") as file:
json.dump(data, file, indent=2)

# 反序列化
with open("data.json", "r") as file:
loaded_data = json.load(file)
print(loaded_data)

对比

特性JavaPython
序列化机制ObjectOutputStreampickle 模块
反序列化机制ObjectInputStreampickle 模块
跨语言支持仅 Javajson 模块支持跨语言
类要求类必须实现 Serializable 接口几乎所有对象都可以序列化
安全性可能存在安全问题pickle 可能存在安全问题,json 更安全

8.4 目录操作

Java 目录操作

// 创建目录
File dir = new File("new_dir");
if (!dir.exists()) {
dir.mkdir();
}

// 列出目录内容
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
System.out.println("File: " + file.getName());
} else if (file.isDirectory()) {
System.out.println("Directory: " + file.getName());
}
}

// 删除目录
if (dir.exists()) {
dir.delete();
}

Python 目录操作

import os

# 创建目录
os.makedirs("new_dir", exist_ok=True) # exist_ok=True 避免目录已存在时出错

# 列出目录内容
for item in os.listdir("new_dir"):
item_path = os.path.join("new_dir", item)
if os.path.isfile(item_path):
print(f"File: {item}")
elif os.path.isdir(item_path):
print(f"Directory: {item}")

# 删除目录
import shutil
shutil.rmtree("new_dir", ignore_errors=True)

# 路径操作
print(os.path.abspath(".")) # 当前目录绝对路径
print(os.path.join("dir1", "dir2", "file.txt")) # 拼接路径
print(os.path.exists("example.txt")) # 检查文件是否存在
print(os.path.isfile("example.txt")) # 检查是否是文件
print(os.path.isdir("new_dir")) # 检查是否是目录

对比

操作JavaPython
创建目录mkdir()os.makedirs()
列出目录listFiles()os.listdir()
删除目录delete()shutil.rmtree()
路径操作File 类方法os.path 模块函数
检查文件存在exists()os.path.exists()

8.5 二进制文件操作

Java 二进制文件操作

try (FileInputStream fis = new FileInputStream("image.jpg")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
// 处理数据
}
} catch (IOException e) {
e.printStackTrace();
}

try (FileOutputStream fos = new FileOutputStream("copy.jpg")) {
byte[] data = new byte[1024];
// 写入数据
fos.write(data);
} catch (IOException e) {
e.printStackTrace();
}

Python 二进制文件操作

# 读取二进制文件
with open("image.jpg", "rb") as file:
data = file.read()
print(f"File size: {len(data)} bytes")

# 写入二进制文件
with open("copy.jpg", "wb") as file:
file.write(data)

# 分块读取大文件
with open("large_file.bin", "rb") as file:
while True:
chunk = file.read(1024) # 每次读取 1024 字节
if not chunk:
break
# 处理 chunk

对比

操作JavaPython
打开模式FileInputStream/FileOutputStreamopen("file", "rb")/open("file", "wb")
读取方式使用字节数组缓冲区直接读取或分块读取
写入方式写入字节数组写入字节对象

8.6 临时文件操作

Java 临时文件操作

try {
File tempFile = File.createTempFile("prefix", ".txt");
tempFile.deleteOnExit(); // JVM 退出时删除

try (FileWriter writer = new FileWriter(tempFile)) {
writer.write("Temporary data");
}

// 使用临时文件
System.out.println("Temp file: " + tempFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}

Python 临时文件操作

import tempfile

# 创建临时文件
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as temp:
temp.write("Temporary data\n")
temp_path = temp.name

print(f"Temp file: {temp_path}")

# 使用临时文件
with open(temp_path, 'r') as file:
content = file.read()
print(content)

# 手动删除
import os
os.unlink(temp_path)

# 临时目录
with tempfile.TemporaryDirectory() as temp_dir:
print(f"Temp directory: {temp_dir}")
# 在临时目录中创建文件
file_path = os.path.join(temp_dir, "test.txt")
with open(file_path, 'w') as file:
file.write("Test data")
# 临时目录自动删除

对比

操作JavaPython
临时文件File.createTempFile()tempfile.NamedTemporaryFile()
临时目录需要手动创建tempfile.TemporaryDirectory()
自动删除deleteOnExit()with 语句自动删除

8.7 IO 异常处理

Java IO 异常处理

try {
// IO 操作
} catch (FileNotFoundException e) {
System.err.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.err.println("IO error: " + e.getMessage());
} finally {
// 清理资源
}

Python IO 异常处理

try:
# IO 操作
with open("nonexistent.txt", "r") as file:
content = file.read()
except FileNotFoundError:
print("File not found")
except IOError as e:
print(f"IO error: {e}")
except Exception as e:
print(f"Error: {e}")

对比

异常类型JavaPython
文件未找到FileNotFoundExceptionFileNotFoundError
IO 错误IOExceptionIOError
异常处理必须捕获检查型异常可以捕获运行时异常

8.8 练习

  1. 文件读写练习:编写程序,读取一个文本文件,统计其中单词的出现次数
  2. 序列化练习:使用 pickle 模块序列化一个对象并保存到文件,然后读取并反序列化
  3. 目录操作练习:编写程序,列出指定目录下的所有文件和子目录
  4. 二进制文件练习:编写程序,复制一个图片文件
  5. 临时文件练习:使用 tempfile 模块创建临时文件并写入数据
  6. 综合练习:编写程序,读取一个 CSV 文件,处理数据后写入新的 CSV 文件

8.9 小结

  • Python 的文件操作比 Java 更简洁,使用 with 语句自动管理资源
  • Python 的 open() 函数支持多种模式,包括文本和二进制模式
  • Python 的 input() 函数比 Java 的 Scanner 更简单
  • Python 的序列化支持 pickle(Python 专用)和 json(跨语言)
  • Python 的目录操作使用 osshutil 模块,比 Java 的 File 类更灵活
  • Python 的临时文件操作使用 tempfile 模块,比 Java 更方便
  • Python 的异常处理更简洁,不需要捕获检查型异常

通过本章的学习,你已经了解了 Java 和 Python 在 IO 操作上的主要区别。接下来,我们将学习 Python 的集合与数据结构。