Android中JDBC连接SQLite数据库失败:只读文件系统错误
这个问题我做Android SQLite相关开发时也碰到过,核心原因是JUnit测试环境和Android应用运行环境的文件系统权限完全不同,咱们一步步拆解清楚:
为什么JUnit测试没问题?
你运行JUnit本地测试时,代码是在电脑的JVM上执行的,"jdbc:sqlite:mydb.sqlite"这个路径指向的是项目根目录(或者测试运行的工作目录),电脑系统对这个目录有完整的读写权限,所以数据库连接完全正常。
为什么Activity里会报错?
但Android应用运行在模拟器的Android系统中时,默认的当前工作目录是应用的安装目录或者系统级目录,这些目录都是只读状态——你直接写mydb.sqlite会尝试在只读目录创建/访问文件,自然就抛出Read-only file system错误了。
解决方案:指定应用有权限的存储路径
Android提供了专门的私有存储目录给应用存放数据,这些目录默认就有读写权限,不需要额外申请权限,推荐用下面两种方式:
1. 使用应用内部私有存储(推荐)
内部存储是应用专属的,其他应用无法访问,适合存放应用的核心数据:
// 在Activity中获取内部存储目录 File dbFile = new File(getFilesDir(), "mydb.sqlite"); // 确保父目录存在(第一次运行时自动创建) dbFile.getParentFile().mkdirs(); // 构建JDBC连接URL final String CONNECTION_URL = "jdbc:sqlite:" + dbFile.getAbsolutePath(); connection = DriverManager.getConnection(CONNECTION_URL);
getFilesDir()返回的路径类似/data/data/你的应用包名/files/,这个路径只有你的应用能读写,安全性很高。
2. 使用应用外部私有存储(可选)
如果你需要让用户能通过文件管理器访问数据库(比如调试用),可以用外部私有存储:
// 获取外部存储的应用私有目录 File externalDir = getExternalFilesDir(null); File dbFile = new File(externalDir, "mydb.sqlite"); dbFile.getParentFile().mkdirs(); final String CONNECTION_URL = "jdbc:sqlite:" + dbFile.getAbsolutePath(); connection = DriverManager.getConnection(CONNECTION_URL);
这个路径类似/storage/emulated/0/Android/data/你的应用包名/files/,Android 10及以上版本不需要申请WRITE_EXTERNAL_STORAGE权限,旧版本可能需要在Manifest里添加权限声明。
额外提示:初始化数据库结构
如果你的数据库需要初始表结构,可以在第一次创建文件时执行初始化逻辑,比如:
if (!dbFile.exists()) { // 执行CREATE TABLE等初始化SQL try (Connection conn = DriverManager.getConnection(CONNECTION_URL); Statement stmt = conn.createStatement()) { stmt.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)"); } catch (SQLException e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者Tanner Barton

