【问题标题】:Android SQLite: W/System.err: java.io.FileNotFoundException Cannot copy database from assetsAndroid SQLite:W/System.err:java.io.FileNotFoundException 无法从资产复制数据库
【发布时间】:2020-04-08 11:53:31
【问题描述】:

我创建了一个包含多个表的数据库。

我在 assets 文件夹中保存了这个数据库。

我试图从这个数据库中简单地访问 EXERCISESTABLE,然后在修改后的 listView 中显示它的值。 但是,我不断收到错误消息:

 W/System.err: java.io.FileNotFoundException.

这是我的 MainActivity 扩展了 Activity 类:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    lvExercise = (ListView)findViewById(R.id.listView_exercises);
    mDBHelper = new DatabaseHelper(this);

    //Check exists database
    File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
    if(false == database.exists()){
        mDBHelper.getReadableDatabase();

        // Copy Database
        if(copyDatabase(this)){
            Toast.makeText(this, "Copy database success", Toast.LENGTH_SHORT).show();
        }else {
            Toast.makeText(this, "Copy data error", Toast.LENGTH_SHORT).show();
            return;
        }
    }
    //Get exercise List in db when db exists
    mExercisesList = mDBHelper.getListExercise();
    //Init adapter
    adapter = new ListExerciseAdapter(this, mExercisesList);
    //Set adapter for list view
    lvExercise.setAdapter(adapter);

}

private boolean copyDatabase(Context context){
    try{
        InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
        String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME;
        OutputStream outputStream = new FileOutputStream(outFileName);
        byte[]buff = new byte[1024];
        int length =0;
        while ((length = inputStream.read(buff)) >0){
            outputStream.write(buff, 0, length);
        }
        outputStream.flush();
        outputStream.close();
        Log.w("MainActivity", "DB copied");
        return true;

    }catch(Exception e){
        e.printStackTrace();
        return false;
    }
}

我的锻炼程序.db 数据库文件位于资产文件夹中,但我似乎无法访问它,即使它看起来对我来说都是正确的。

这是我的 DBHelper 扩展 SQLiteOpenHelper 代码:

private Context mContext;
private SQLiteDatabase mDatabase;

public DatabaseHelper(Context context){
    super(context, DBNAME, null, 1);
    this.mContext = context;

}
@Override
public void onCreate(SQLiteDatabase db) {


}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}
public void openDatabase() {
    String dbPath = mContext.getDatabasePath(DBNAME).getPath();
    if(mDatabase != null && mDatabase.isOpen()){
        return;
    }
    mDatabase = SQLiteDatabase.openDatabase(dbPath,null,SQLiteDatabase.OPEN_READWRITE);
}

public void closeDatabase(){
    if(mDatabase!=null){
        mDatabase.close();
    }
}

public List<Exercise> getListExercise(){
    Exercise exercise = null;
    List<Exercise> exerciseList = new ArrayList<>();
    openDatabase();
    Cursor cursor = mDatabase.rawQuery("SELECT * FROM EXERCISESTABLE ", null);
    cursor.moveToFirst();
    while(!cursor.isAfterLast()){
        exercise = new Exercise(cursor.getInt(0),cursor.getString(1), cursor.getInt(2), cursor.getInt(3));
        exerciseList.add(exercise);
        cursor.moveToNext();
        closeDatabase();

    }
    return exerciseList;
}

这是我的运动课:

public class Exercise {
private int exercise_id;
private String exercise_name;
private int exercise_type_id;
private int exercise_equipment_id;

public Exercise(int exercise_id, String exercise_name, int exercise_type_id, int exercise_equipment_id) {
    this.exercise_id = exercise_id;
    this.exercise_name = exercise_name;
    this.exercise_type_id = exercise_type_id;
    this.exercise_equipment_id = exercise_equipment_id;
}

public int getExercise_id() {
    return exercise_id;
}

public void setExercise_id(int exercise_id) {
    this.exercise_id = exercise_id;
}

public String getExercise_name() {
    return exercise_name;
}

public void setExercise_name(String exercise_name) {
    this.exercise_name = exercise_name;
}

public int getExercise_type_id() {
    return exercise_type_id;
}

public void setExercise_type_id(int exercise_type_id) {
    this.exercise_type_id = exercise_type_id;
}

public int getExercise_equipment_id() {
    return exercise_equipment_id;
}

public void setExercise_equipment_id(int exercise_equipment_id) {
    this.exercise_equipment_id = exercise_equipment_id;
}

}

这是我的 ListExerciseAdapter 扩展 BaseAdapter 类:

public ListExerciseAdapter(Context mContext, List<Exercise> exercisesList) {
    this.mContext = mContext;
    this.mExercisesList = exercisesList;
}

@Override
public int getCount() {
    return mExercisesList.size();
}

@Override
public Object getItem(int position) {
    return mExercisesList.get(position);
}

@Override
public long getItemId(int position) {
    return mExercisesList.get(position).getExercise_id();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View v = View.inflate(mContext, R.layout.exercises_listview_layout, null);
    TextView exercise_name = (TextView)v.findViewById(R.id.exercise_name);
    TextView exercise_type_id = (TextView)v.findViewById(R.id.exercise_type_id);
    TextView exercise_equipment_id = (TextView)v.findViewById(R.id.exercise_equipment_id);

    exercise_name.setText(mExercisesList.get(position).getExercise_name());
    exercise_type_id.setText(String.valueOf(mExercisesList.get(position).getExercise_type_id()));
    exercise_equipment_id.setText(String.valueOf(mExercisesList.get(position).getExercise_equipment_id()));
    return v;
}

任何帮助将不胜感激。

【问题讨论】:

    标签: java android database sqlite filenotfoundexception


    【解决方案1】:

    根据来自official documentation 的预填充房间数据库。你有两个选择:

    1) createFromAssets:在此选项中,您可以在 assets 文件夹下创建一个名为“databases”的目录 所以你的可能如下:

    .createFromAssets("/databases/YOUR DATABASE FILENAME")
    

    2) createFromFile:此选项可能适用于您为其分配路径的文件。

    .createFromFile(File("YOUR FILE PATH"))
    

    如果您对这两种解决方案感到困惑,您可以尝试手动解决方案,我们可以称之为手动解决方案是啊!。通过访问资产文件夹中的数据库文件。

        private fun copyDBFromStorage(databaseName: String) {
        if (checkIfDBExists(this, databaseName)) return
        val databaseFile = File(this.getDatabasePath(databaseName).toString())
        val sourceLocation = assets.open("Your database file path")
        try {
            val inputStream = sourceLocation
            val os = FileOutputStream(databaseFile)
            val buffer = ByteArray(1024 * 32)
            var length = inputStream.read(buffer)
            while (length > 0) {
                os.write(buffer, 0, length)
                length = inputStream.read(buffer)
            }
            os.flush()
            os.close()
            inputStream.close()
    
        } catch (ex: IOException) {
            ex.printStackTrace();
            throw  RuntimeException("Error copying storage database");
        }
    }
    
    private fun checkIfDBExists(
        context: Context,
        databaseName: String
    ): Boolean {
        val dbfile = File(context.getDatabasePath(databaseName).toString())
        if (dbfile.exists()) return true
        if (!dbfile.parentFile.exists()) {
            dbfile.parentFile.mkdirs()
        }
        return false
    }
    

    注意:您可以使用 android studio 代码转换功能将此 Kotlin 代码转换为 java。

    如果您发现任何问题,请回复。

    快乐编码?

    【讨论】:

    • 谢谢。请您澄清一下我会在哪里打电话:.createFromAssets("/databases/YOUR DATABASE FILENAME")
    • 您应该使用 Room 库才能使用 createFromAssets()。如果您不使用 Room,您可以选择第三个选项。您应该调用一次(或者这取决于您的业务)。我建议将共享首选项与名为“firstRun”的布尔对象一起使用。当第一次运行为 true 时,从资产中复制数据库并将 false 分配给 firstRun 对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多