Room数据库导入JSON文件时触发FileNotFoundException异常求助
问题排查与解决方案
你的问题根源在于Room的createFromAsset()方法的路径使用错误,下面详细说明问题原因和两种解决办法:
为什么会报FileNotFoundException?
createFromAsset()是专门用来读取项目assets目录下的文件的,而你把cars_sample.json放在了res/raw目录里,这两个目录的文件访问规则完全不同:
res/raw里的文件会被Android编译系统分配资源ID(比如R.raw.cars_sample),不能通过文件路径直接访问assets目录下的文件则是按原始文件名和路径访问,不会生成资源ID
你传入的"app/res/raw/cars_sample.json"既不是assets目录下的正确路径,也不符合res/raw的访问方式,所以系统找不到文件。
解决方案1:将JSON文件移到assets目录(推荐)
这是最符合createFromAsset()设计的方式,步骤如下:
- 如果你的项目没有
assets目录,在app/src/main下新建一个(目录结构:app/src/main/assets) - 把
res/raw里的cars_sample.json剪切到assets目录中 - 修改你的Database初始化代码,把路径改为文件名即可:
fun getInstance(context: Context): CarDatabase { if(instance == null) { instance = Room.databaseBuilder( context, CarDatabase::class.java, "cars_table" ).createFromAsset("cars_sample.json").build() // 这里直接用文件名 } return instance as CarDatabase }
解决方案2:保留文件在res/raw,手动读取并填充数据
如果不想移动文件,可以通过Room的回调机制,在数据库创建时手动读取raw目录的JSON并插入数据:
- 确保你的Dao层有批量插入的方法,比如:
@Dao interface CarDao { @Insert fun insertAll(cars: List<Car>) }
- 修改Database的初始化代码,添加
addCallback:
fun getInstance(context: Context): CarDatabase { if(instance == null) { instance = Room.databaseBuilder( context, CarDatabase::class.java, "cars_table" ).addCallback(object : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) // 读取raw中的JSON文件 val jsonContent = context.resources.openRawResource(R.raw.cars_sample) .bufferedReader() .use { it.readText() } // 解析JSON为实体列表(这里用Gson举例,你也可以用其他解析库) val carList = Gson().fromJson(jsonContent, Array<Car>::class.java).toList() // 开启子线程插入数据(不能在主线程操作数据库) Thread { instance?.carDao()?.insertAll(carList) }.start() } }).build() } return instance as CarDatabase }
- 如果用Gson解析,需要在
app/build.gradle(Module级)添加依赖:
implementation 'com.google.code.gson:gson:2.10.1'
内容的提问来源于stack exchange,提问作者SNM
相关产品推荐
相关产品推荐

