QPython 文件路径问题——FileNotFoundError、PermissionError、硬编码路径踩坑
常见路径报错
在 QPython 中操作文件时最常遇到的两个报错:
FileNotFoundError
脚本说找不到某个文件,但你明明记得文件存在。
PermissionError
脚本说没有权限读写某个路径下的文件。
根本原因
Android 采用沙盒机制——每个 App 只能直接访问自己的私有目录(内部存储)和有限的公共目录(外部存储)。直接写硬编码路径(如 /sdcard/Download/xxx.py)在很多手机上会失败,因为 Android 的存储访问框架(SAF)不让 QPython 直接越过沙盒访问其他 App 的目录。
正确的路径获取方式
方式一:os.getcwd() 看当前工作目录
import os
print(os.getcwd()) # 当前工作目录
print(os.listdir(".")) # 当前目录下有什么
这是最基础也是最重要的一步。先搞清楚脚本当前在哪个目录下运行。
方式二:QSL4A 获取外部存储路径
from androidhelper import Android
droid = Android()
print(droid.getExternalStoragePath())
返回的是 QPython 可以访问的外部存储根路径。
方式三:构造相对路径
最简单可靠的路径策略——永远用相对路径(相对于当前工作目录):
# 好
with open("my_data.csv", "r") as f:
data = f.read()
# 不推荐
with open("/sdcard/Download/my_data.csv", "r") as f:
data = f.read()
QEditor 保存的 .py 文件、通过 open() 创建的新文件,默认都在 QPython 的当前工作目录下,相对路径永远能找到它们。
路径问题排查清单
脚本报文件相关错误时,按这个顺序排查:
1. 确认目录存在
import os
print(f"工作目录: {os.getcwd()}")
print(f"目标目录存在: {os.path.exists('目标目录名')}")
print(f"目标文件存在: {os.path.exists('目标文件名')}")
2. 确认权限已授予
读取 / 写入文件需要存储权限。检查:
- 读取文件与文档:已授予
- 写入文件与文档:已授予
- 管理所有文件:访问公共目录时需要(可选)
3. 确认路径格式
Android 路径用 / 分隔(和 Windows 不同):
- 正确:
/storage/emulated/0/Download/file.py - 错误(Windows 风格):
\sdcard\Download\file.py
Python 的 os.path 会自动适配平台,所以构造路径时用 os.path.join:
import os
target_path = os.path.join(os.getcwd(), "subdir", "file.txt")
4. 检查中文文件名
极少数情况下,文件包含中文字符可能导致路径解析问题。如果你怀疑是中文的问题,临时把文件改个英文名字再试。
5. 检查文件是否真的存在于磁盘
有时候 QEditor 里你觉得文件存了,但其实没存成功:
- 在 QEditor 里重新打开文件确认内容在
- 用文件管理器(或 QPython 的文件浏览器)检查文件确实在磁盘上
跨目录文件操作
同目录
最简单,直接用文件名:
with open("data.csv", "r") as f:
data = f.read()
子目录
用相对路径:
import os
# 假设当前目录下有 data/ 子目录
file_path = os.path.join("data", "sensor_20240101.csv")
with open(file_path, "r") as f:
data = f.read()
外部公共目录(Download、Documents 等)
这需要存储权限(特别是「管理所有文件」)。确认权限后:
download_path = os.path.join("/storage/emulated/0", "Download", "target.csv")
# 或用 QSL4A
from androidhelper import Android
droid = Android()
# SAF 选择文件后会返回可访问的路径
不同 Android 版本对公共目录的限制不同。Android 11+ 对 Download 等目录的限制非常严格,即使有存储权限也不一定能直接读写。
其他 App 的数据
基本不可能。Android 沙盒隔离了每个 App 的数据目录,QPython 不能直接访问微信、QQ、相机等 App 的私有数据。如果需要其他 App 里的数据:
- 让那个 App 导出到公共目录(如微信文件传输助手保存到 Download)
- 或在 QPython 里用
droid.webViewShow()打开网页版手动下载 - 或通过 QSL4A 的
droid.contentQuery()查询(某些版本支持)
路径问题快捷诊断脚本
在 REPL 里直接跑,帮你快速看清楚 QPython 能访问哪些路径:
import os
from androidhelper import Android
droid = Android()
print("=== 路径自检 ===")
print(f"1. 当前工作目录: {os.getcwd()}")
print(f"2. 工作目录内容: {os.listdir('.')[:10]}...") # 前 10 项
print(f"3. 外部存储路径: {droid.getExternalStoragePath()}")
print(f"4. 存储总空间: {droid.getExternalStorageTotalSize()} 字节")
print(f"5. 存储剩余空间: {droid.getExternalStorageAvailableSize()} 字节")
# 测试当前目录是否可写
test_file = "test_write_permission.tmp"
try:
with open(test_file, "w") as f:
f.write("test")
os.remove(test_file)
print("6. 当前目录可写: YES")
except Exception as e:
print(f"6. 当前目录可写: NO ({e})")
# 测试能否访问 Download 目录
try:
dl_path = os.path.join("/storage/emulated/0", "Download")
os.listdir(dl_path)
print("7. Download 目录可访问: YES")
except Exception as e:
print(f"7. Download 目录可访问: NO ({e})")
print("=== 自检完成 ===")
小结
路径问题的根因是 Android 沙盒机制——App 不能随便访问任意路径。最好的策略是永远用相对路径、永远在 QPython 的工作目录和子目录里读写文件。访问外部公共目录(Download 等)需要额外的存储权限,且受 Android 版本影响。跨 App 数据访问基本不可能——需要用导出到公共目录的方式间接获取。
全部 12 组页面 + 首页 + 图片下载到此完成。现在跑渲染校验。