Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/180.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android:从资产文件夹复制数据库,但只获取一个空文件_Android_Sqlite_Android Assets - Fatal编程技术网

Android:从资产文件夹复制数据库,但只获取一个空文件

Android:从资产文件夹复制数据库,但只获取一个空文件,android,sqlite,android-assets,Android,Sqlite,Android Assets,伙计们,我在将数据库从本地资产文件夹复制到/data/data/package\u name/databases目录时遇到了问题。当我使用教程来做这件事时,我只能得到一个空文件 我引用了copyDataBase()方法的一部分,没有区别。每次应用程序启动时,它都会创建目录和空数据库。那么有没有办法让copyDataBase()工作呢 非常感谢 我不会从资产-文件夹复制任何数据库。如果数据库中需要一些标准条目,可以使用onCreate()-方法中的INSERTs添加它们 更新:因为这被认为是错误

伙计们,我在将数据库从本地资产文件夹复制到/data/data/package\u name/databases目录时遇到了问题。当我使用教程来做这件事时,我只能得到一个空文件

我引用了copyDataBase()方法的一部分,没有区别。每次应用程序启动时,它都会创建目录和空数据库。那么有没有办法让copyDataBase()工作呢

非常感谢

我不会从
资产
-文件夹复制任何数据库。如果数据库中需要一些标准条目,可以使用
onCreate()
-方法中的
INSERT
s添加它们


更新:因为这被认为是错误的(有点正确),我不能删除它,所以这里有一个小的更新

我想说,这取决于要添加到数据库中的标准条目的数量。如果只是一个或两个,运送打包的DB可能不值得

无论如何,有些应用程序附带了相当大的数据库(例如,配方集合)。显然,您不能在代码中添加所有这些内容

  • 对于小的测试条目,我仍然更喜欢简单地将它们添加到
    onCreate()
  • 对于更大的数据库,您应该预先填充它们,并将它们与应用程序一起发布

为了使以后的工作正常,您需要将数据库文件从
assets/
复制到您的应用程序文件夹中。有一个很好的库可以为您处理这个问题:

为什么不从资产中复制?这样做是完全正常的。但是不能在onCreate中执行此操作,此时已经创建了一个空数据库。你需要事先做这件事。我通常在覆盖getWriteableDatabase时这样做,比如

public synchronized SQLiteDatabase getWritableDatabase() {
    SQLiteDatabase db = null;

    if (!doesDatabaseExist()) {
        try {
            copyDatabase();
            db = super.getWritableDatabase();
        } catch(Exception ex) {
            Log.e("Database Log", getDatabasePath() + " failed to copy correctly. " + ex.getLocalizedMessage());
        }
    }
    else {
        db = super.getWritableDatabase();
    }

    return db;
}

在右上方的示例中,我的工作方式如下:

db = super.getWritableDatabase();
db.close;
copyDatabase();

否则我会得到一个IO错误

以下是我使用的简单方便的代码:

public class DataBaseImportHelper {
    private DataBaseImportHelper() {}; // Avoid instantiation

/**
 * Creates a empty database on the system and rewrites it with your own database.
 */
public static boolean importDataBase(Context context) {
    InputStream myInput = null;
    OutputStream myOutput = null;
    try {
        // Open local db from assets as the input stream
        myInput = context.getAssets().open(DATABASE_NAME);
        createEmptyDatabase(context); // See this method below
        // Open the empty db as the output stream
        myOutput = new FileOutputStream(getDatabaseFile(context));

        // transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }

        // Close the streams
        myOutput.flush();
        myInput.close();
        myOutput.close();
        return true;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

/**
 * Check if the database already exists.
 * @return true if it exists, false if it doesn't
 */
public static boolean isDatabaseExists(Context context) {
    return getDatabaseFile(context).exists();
}

private static File getDatabaseFile(Context context) {
    return context.getDatabasePath(DatabaseHelper.DATABASE_NAME);
}

/**
 * Create an empty database into the default application database
 * folder.So we are gonna be able to overwrite that database with our database
 */
private static void createEmptyDatabase(Context context) {
            // use anonimous helper to create empty database
    new SQLiteOpenHelper(context, DatabaseHelper.DATABASE_NAME, null, 1) {
                    // Methods are empty. We don`t need to override them
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
        }
    }.getReadableDatabase().close();
}
}

并在代码中使用:

if(!DataBaseImportHelper.isDatabaseExists(this)){
    if (!DataBaseImportHelper.importDataBase(this)){
            throw new IllegalStateException("Database doesn`t exist and hasn`t been copied!");
    }
}

我不知道它是否仍然有用,但这里有一个解决方案,供其他来到这里观看awnser的人使用。您使用的代码适用于大多数手机,一些较旧的手机在getReadableDatabase()函数中有不同的行为。因此,问题不在于copyDataBase函数,而在于createDataBase函数

在createDataBase()中有以下检查:

this.getReadableDatabase();
这将检查是否已经存在具有所提供名称的数据库,如果没有,将创建一个空数据库,以便可以使用资产文件夹中的数据库覆盖该数据库。在较新的设备上,这可以完美地工作,但也有一些设备无法工作。主要是老式设备。我不知道确切的原因,但getReadableDatabase()函数似乎不仅可以获取数据库,还可以打开它。如果您随后将数据库从资产文件夹复制到它上面,它仍然有指向空数据库的指针,并且您将得到表不存在错误

因此,为了使其在所有设备上工作,您应该将其修改为以下行:

SQLiteDatabase db = this.getReadableDatabase();
if (db.isOpen()){
    db.close();
}

即使在检查中打开了数据库,之后它也会关闭,不会给您带来任何麻烦。

谢谢!这只是两个小时的工作。:)为什么不从资产中复制db文件?在我的例子中,它是一个R/O数据库,有19个表和35k行insert语句。我看不出为什么要在设备上初始化这样的数据库。是否有我遗漏的内容?是否有不需要复制到数据文件夹的方法?我们可以直接从资产文件夹中读取吗?您的数据库有多大?可能是我的作品(安卓2.3.3)。干净坚实。我必须对它做一点修改:
如果(!doesDatabaseExist()){try{SQLiteDatabase db=super.getReadableDatabase();db.close();}catch(异常忽略){}copyFromAssets();return super.getReadableDatabase();}
否则它会因FileNotFoundException而崩溃,可能是因为数据库目录不存在。(Android 2.2)关键是调用createEmptyDatabase()。如果不这样做,对“new FileOutputStream()”的调用将失败,即使该文件不存在时应该创建该文件。