Python实现文件传输功能时,开发者常会遇到目录相关错误以及其他运行异常,这些问题如果不妥善处理,会导致传输流程中断、文件损坏甚至程序崩溃。下面结合实际开发场景,逐一分析问题的产生原因并给出修复方法。

一、常见的目录错误及修复
1. 目录不存在导致的文件写入失败
接收端保存文件时如果目标目录不存在,会直接抛出FileNotFoundError。修复方法是在写入文件前先检查目录是否存在,不存在则自动创建。
import os
def ensure_dir(dir_path):
# 检查目录是否存在,不存在则递归创建
if not os.path.exists(dir_path):
os.makedirs(dir_path)
return dir_path
# 接收端保存文件的目录
save_dir = "./received_files"
file_name = "test.txt"
# 确保目录存在后再拼接完整路径
full_path = os.path.join(ensure_dir(save_dir), file_name)
2. 路径拼接错误导致文件找不到
手动拼接路径时容易出现斜杠不统一、多拼接或少拼接字符的问题,建议使用os.path.join方法自动处理路径分隔符,避免跨平台兼容性问题。
import os
# 错误示例:手动拼接路径,Windows和Linux分隔符不统一
wrong_path = "./files/" + "data.txt" # 可能在部分系统下失效
# 正确示例:使用os.path.join拼接
correct_path = os.path.join(".", "files", "data.txt")
print(correct_path) # 自动适配当前系统的路径格式
二、其他高频问题及修复方案
1. 传输大文件时的内存溢出问题
如果一次性读取整个文件再发送,大文件会占用大量内存导致程序崩溃,正确的做法是分块读取和发送。
# 发送端分块发送文件
def send_file(sock, file_path, chunk_size=1024):
with open(file_path, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
# 发送数据块
sock.sendall(chunk)
# 发送结束标志
sock.sendall(b"EOF")
# 接收端分块接收文件
def recv_file(sock, save_path, chunk_size=1024):
with open(save_path, "wb") as f:
while True:
chunk = sock.recv(chunk_size)
if not chunk:
break
if chunk.endswith(b"EOF"):
# 去掉结束标志后写入
f.write(chunk[:-3])
break
f.write(chunk)
2. 编码不一致导致的文件名乱码
传输文件名时如果编码和解码不一致,会出现中文文件名乱码的问题,建议统一使用UTF-8编码处理文件名。
# 发送端发送文件名
file_name = "测试文件.txt"
# 编码为UTF-8字节流发送
sock.sendall(file_name.encode("utf-8"))
# 接收端接收文件名
raw_name = sock.recv(1024)
# 使用UTF-8解码
file_name = raw_name.decode("utf-8")
print(f"接收到的文件名:{file_name}")
3. 连接异常未处理导致程序崩溃
传输过程中如果网络中断,会抛出连接异常,需要添加异常捕获逻辑,保证程序不会直接崩溃。
import socket
def safe_transfer(sock, file_path):
try:
send_file(sock, file_path)
print("文件传输完成")
except socket.error as e:
print(f"传输过程出现异常:{e}")
except Exception as e:
print(f"其他异常:{e}")
finally:
# 无论是否异常都关闭连接
sock.close()
三、完整可运行的修复后示例
下面是一个简单的基于socket的文件传输完整示例,已经修复了上述提到的目录错误和其他常见问题。
import socket
import os
# 确保目录存在
def ensure_dir(dir_path):
if not os.path.exists(dir_path):
os.makedirs(dir_path)
return dir_path
# 分块发送文件
def send_file(sock, file_path, chunk_size=1024):
with open(file_path, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
sock.sendall(chunk)
sock.sendall(b"EOF")
# 分块接收文件
def recv_file(sock, save_path, chunk_size=1024):
with open(save_path, "wb") as f:
while True:
chunk = sock.recv(chunk_size)
if not chunk:
break
if chunk.endswith(b"EOF"):
f.write(chunk[:-3])
break
f.write(chunk)
# 服务端(接收端)
def server():
save_dir = ensure_dir("./received_files")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1", 8888))
s.listen(1)
print("服务端启动,等待连接...")
conn, addr = s.accept()
print(f"客户端{addr}已连接")
# 接收文件名
raw_name = conn.recv(1024).decode("utf-8")
save_path = os.path.join(save_dir, raw_name)
# 接收文件
recv_file(conn, save_path)
print(f"文件已保存到{save_path}")
conn.close()
s.close()
# 客户端(发送端)
def client(file_path):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 8888))
# 发送文件名
file_name = os.path.basename(file_path)
s.sendall(file_name.encode("utf-8"))
# 发送文件
send_file(s, file_path)
print("文件发送完成")
s.close()
if __name__ == "__main__":
# 先启动服务端,再启动客户端,传入要发送的文件路径
# server()
# client("./test.txt")
pass
按照上述方法修复后,Python文件传输代码的稳定性会大幅提升,开发者可以根据实际业务需求调整分块大小、添加传输进度提示等功能,进一步优化使用体验。