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

发布于 2024-11-09 17:21:17 字数 407 浏览 4 评论 0原文

伙计们,我在将数据库从本地资产文件夹复制到 /data/data/package_name/databases 目录时遇到问题。当我使用 http://www. iredesign.com/blog/using-your-own-sqlite-database-in-android-applications/教程来做到这一点,我只能得到一个空文件。

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

非常感谢!!

guys, I have the problem when copying database from local assets folder to /data/data/package_name/databases directory. As I use the http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/ tutorial to do it, I can only get an empty file.

I quoted the part of copyDataBase() method and there is no difference. Every time the app start, it will create the directory and empty database. So is there any way to make the copyDataBase() work?

Thank you very much!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

淡写薰衣草的香 2024-11-16 17:21:17

为什么不从资产中复制?这样做是完全正常的。但你不能在 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;
}

Why wouldn't you copy from assets? It's perfectly normal to do so. But you can't do it in the onCreate, at that point an empty database is already created. You need to do it prior. I usually do it in an override of getWriteableDatabase, something like

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;
}
一抹淡然 2024-11-16 17:21:17

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

在 createDataBase() 中有以下检查;

this.getReadableDatabase();

这将检查是否已经存在具有所提供名称的数据库,如果没有,则创建一个空数据库,以便可以用资产文件夹中的数据库覆盖它。在较新的设备上,此功能可以完美运行,但在某些设备上,此功能不起作用。主要是旧设备。我不知道到底为什么,但 getReadableDatabase() 函数似乎不仅获取数据库而且还打开它。如果您随后从资产文件夹中复制数据库,它仍然具有指向空数据库的指针,并且您将收到表不存在错误。

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

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

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

I don't know if it is still usefull but here is the solution for others that get here to see the awnser. The code you used, works for most phones, some older phones have different behaviour with the getReadableDatabase() function. Your problem therefore is not in the copyDataBase function but in the createDataBase function.

in createDataBase() there is the following check;

this.getReadableDatabase();

This checks if there is already a database with the provided name and if not creates an empty database such that it can be overwritten with the one in the assets folder. On newer devices this works flawlessly but there are some devices on which this doesn't work. Mainly older devices. I do not know exactly why, but it seems like the getReadableDatabase() function not only gets the database but also opens it. If you then copy the database from the assets folder over it, it still has the pointer to an empty database and you will get table does not exist errors.

So in order to make it work on all devices you should modify it to the following lines:

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

Even if the database is opened in the check, it is closed thereafter and it will not give you any more trouble.

戏蝶舞 2024-11-16 17:21:17

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


更新:由于这因错误而被否决(这有点正确)并且我无法删除它,所以这里有一个小更新。

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

无论如何,一些应用程序带有相当大的数据库(例如,食谱集合)。显然你不能在代码中添加所有这些。

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

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

I wouldn't copy any database form the assets-folder. If you need some standard entry's in your Database, you can add them using INSERTs in your onCreate()-method.


Update: Since this is getting down-voted for being wrong (which is kinda right) and I can't delete it, here is a little update.

I'd say it depends upon how many standard entries you want to add to your database. If it's just one or two, shipping a packed DB might not be worth it.

Anyways, some apps come with rather large databases (for example, a recipe collection). You can obviously not add all these in code.

  • For small test-entries, I'd still prefer simply adding them in onCreate().
  • For bigger databases, you should pre-populate them and ship em along with your app.

For the later to work, you'll need to copy the database file from assets/ to your app-folder. There is a nice library to handle that for you: android-sqlite-asset-helper

屋顶上的小猫咪 2024-11-16 17:21:17

上面的例子对我来说是这样的:

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

否则我会得到一个 IO 错误;

at the right above example worked for me this way:

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

otherwise i got an IO error;

无可置疑 2024-11-16 17:21:17

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

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!");
    }
}

Here is the simple and convenient code which I use:

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();
}

}

And using in code:

if(!DataBaseImportHelper.isDatabaseExists(this)){
    if (!DataBaseImportHelper.importDataBase(this)){
            throw new IllegalStateException("Database doesn`t exist and hasn`t been copied!");
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文