资产文件夹中大于 1MB 的安卓数据库



所以我有这个大约 7MB 的数据库,当我在 2014 年第一次开始开发应用程序时,我读到我应该将数据库分成 1MB 的部分并将其放在 assets 文件夹中,如下所示: 01.db 02.db 03.db ... 07.db

在我的数据库助手类上,我有

private void copyDataBase(File DBFile) throws IOException
{
AssetManager am = myContext.getAssets();
OutputStream os = new FileOutputStream(DBFile);
DBFile.createNewFile();
byte []b = new byte[1024];
int i, r;
String []Files = am.list("");
Arrays.sort(Files);
for(i=1;i<15;i++) //I have definitely less than 10 files; you might have more
{
String fn = String.format("0%d.db", i);
System.out.println(fn);
if(Arrays.binarySearch(Files, fn) < 0) //No such file in assets - time to quit the loop
break;
InputStream is = am.open(fn);
while((r = is.read(b)) != -1)
os.write(b, 0, r);
is.close();
}
os.close();
}

这段代码是否仍然相关?这是我的完整数据库助手类,你们中的任何人都有它的更新版本吗?数据库助手.class

public class DatabaseHelper extends SQLiteOpenHelper {
private SQLiteDatabase myDataBase;
private final Context myContext;
//public static String PACKAGE_NAME
//PACKAGE_NAME = getApplicationContext().getPackageName();
//The Androids default system path of your application database.
//private static String DB_PATH = "/data/data/"+PACKAGE_NAME+"/databases/";
private static String DB_PATH = "";
private static String DB_NAME = "fulldb6";//name of your Database
//File DBFile                 = new File(DB_PATH, DB_NAME);
File DBFile;

/**
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources.
* @param context
*/
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, 3);
this.myContext = context;
DB_PATH = myContext.getDatabasePath(this.DB_NAME).getPath();;
DBFile  = myContext.getDatabasePath(this.DB_NAME);
//System.out.println(DBFile.getPath());
}
/**
* Creates a empty database on the system and rewrites it with your own database.
* */
public void createDataBase() throws IOException{
boolean dbExist = checkIfDataBaseExists();
if(dbExist){
//do nothing - database already exist
} else{
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase(DBFile);
} catch (IOException e) {
throw new Error("Error copying database");
}
}

}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* @return true if it exists, false if it doesn't
*/
private boolean checkIfDataBaseExists(){
SQLiteDatabase checkDB = null;
try{
String myPath = DB_PATH;
checkDB       = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
} catch(SQLiteException e){

}
if(checkDB != null){
checkDB.close();
}
return checkDB != null ? true : false;
}

private void copyDataBase(File DBFile) throws IOException
{
AssetManager am = myContext.getAssets();
OutputStream os = new FileOutputStream(DBFile);
DBFile.createNewFile();
byte []b = new byte[1024];
int i, r;
String []Files = am.list("");
Arrays.sort(Files);
for(i=1;i<15;i++) //I have definitely less than 10 files; you might have more
{
String fn = String.format("0%d.db", i);
System.out.println(fn);
if(Arrays.binarySearch(Files, fn) < 0) //No such file in assets - time to quit the loop
break;
InputStream is = am.open(fn);
while((r = is.read(b)) != -1)
os.write(b, 0, r);
is.close();
}
os.close();
}

public void openDataBase() throws SQLException{
//Open the database
String myPath = DB_PATH ;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
@Override
public synchronized void close() {
if(myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}

还有谁知道将db_path硬编码为/data/data/com.packagename/databases 是否会导致任何崩溃?在没有内存的设备中,也许db存储在SD卡上?许多人报告了崩溃或无法正常工作的应用程序,我无法在我的设备和 android 模拟器上复制这些应用程序。

我应该检查一下,如果没有内存在SD卡中安装db?

这段代码仍然相关吗?

这将导致 Android 9+失败,因为 getReadableDatabase 将导致创建 -wal 和 -shm 文件(在 Android 9+ 中默认打开 WAL (,这些文件被标记为由新数据库拥有。新数据库被覆盖,但 -wal 和 -shm 文件仍然存在。复制有效,但是当通过 SQliteOpenHelper 打开数据库时,由于 -shm 和 -wal 文件存在的错误导致可用数据库为空,即数据已被擦除,通常应用程序将崩溃,找不到表。

我怀疑,使用getReadableDatabase或(getWritableDatabase没有区别,除非发生灾难(被历史使用的唯一原因是有人发现它在不使用OpenError ENOENT时绕过了OpenError ENOENT。怎么回事???数据库作为打开数据库的漫长而曲折过程的一部分,如果数据库目录不存在,则创建数据库目录。

我不知道为什么没有使用mkdirs的明显用途。

检查和准备从资产复制数据库文件的有效方法是检查数据库文件是否存在(如果存在,则无需从资产复制(,如果不存在,则检查文件的父文件(数据库文件夹(以查看它是否存在。如果它不存在,则在父文件上执行mkdirs,然后复制该文件。

  • 无需不必要地打开数据库文件,
  • 不生成 -wal 和 -SWM 文件,
  • 没有底层处理来创建数据库文件、-shm 文件和 -wal 文件,只是为了丢弃它们。 -没有消失的桌面技巧。
/data/

data/com.packagename/databases

由于问题(主要是错别字(,提出了许多问题。但是,无需硬编码。使用ContextgetDatabasePath(dbname(方法返回路径。唯一的硬代码(应该是 1 位作为常量(是数据库名称(在您的情况下DB_NAME(。

所以我有这个大约 7MB 的数据库,当我在 2014 年第一次开始开发应用程序时,我读到我应该将数据库分成 1MB 的部分并将其放在 assets 文件夹中,如下所示:01.db 02.db 03.db ...07.db

我认为这种限制仍然存在。我相信资产可以成为APK的100mb的一部分,但更大的数据可以通过扩展APK处理。

最新更新