英文:
Android SQLite: W/System.err: java.io.FileNotFoundException Cannot copy database from assets
问题
我创建了一个包含多个表的数据库。
我将这个数据库保存在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);
//检查数据库是否存在
File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
if(false == database.exists()){
mDBHelper.getReadableDatabase();
// 复制数据库
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;
}
}
//数据库存在时从数据库获取运动列表
mExercisesList = mDBHelper.getListExercise();
//初始化适配器
adapter = new ListExerciseAdapter(this, mExercisesList);
//为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;
}
}
我的workout_program.db数据库文件位于assets文件夹中,但是尽管看起来一切都正确,我似乎无法访问它。
以下是我的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();
}
cursor.close();
closeDatabase();
return exerciseList;
}
以下是我的Exercise类:
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;
}
任何帮助将不胜感激。
英文:
I created a database containing several tables.
I have this database saved in the assets folder.
I am trying to simply access the EXERCISESTABLE from this database and then display its values in a modified listView.
However, I keep getting the error:
W/System.err: java.io.FileNotFoundException.
Here is my MainActivity extends Activity Class:
@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;
}
}
I have my workout_program.db database file located in the assets folder, however I cant seem to access it even though it all looks correct to me.
Here is my DBHelper extends SQLiteOpenHelper Code:
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;
}
Here is my exercise class:
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;
}
}
Here is my ListExerciseAdapter extends BaseAdapter class:
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;
}
Any help will be greatly appreciated.
答案1
得分: 1
根据官方文档中提供的预填充 Room Database,你有两个选项:
-
createFromAssets:在此选项中,你可以在 assets 文件夹下创建一个名为 "databases" 的目录,使你的代码如下:
.createFromAssets("/databases/YOUR DATABASE FILENAME")
-
createFromFile:此选项可以使用你分配路径的文件。
.createFromFile(File("YOUR FILE PATH"))
如果你在这两个解决方案中遇到问题,你可以尝试手动解决方案,我们称之为手动解决方案!通过访问位于 assets 文件夹中的数据库文件。
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 代码。
如果你遇到任何问题,请回复。
愉快编码!🤓
英文:
According to the prepopulated Room Database from the official documentation. You have 2 options:
-
createFromAssets: in this option, you may create a directory called "databases" under assets folder
so your could will be as follow:.createFromAssets("/databases/YOUR DATABASE FILENAME")
-
createFromFile: This option may work with the file you are assigning its path.
.createFromFile(File("YOUR FILE PATH"))
if you are stuck with these two solutions, you can try the manual solution, we may call it manual solution yeah !. by accessing your database file in assets folder.
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
}
Note: you can convert this Kotlin code to java using android studio code conversion feature.
If you found any problem with that, kindly reply.
Happy coding 🤓
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论