我发布了一个有sqlite数据库的应用,但是我收到了一些用户的错误(超过99%的用户没有收到错误),但每天发送一两封我这个痕迹:
java.lang.Error:/data/data/(POPAGENAME)/databases/(FILENAME).sqlite:open failed:ENOENT(没有这样的文件或目录)
这是我的代码:
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME+".sqlite");
String outFileName = Environment.getDataDirectory() + "/data/"+context.getPackageName()+"/databases/"+ DB_NAME+".sqlite";
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
我感到困惑,因为它适用于所有智能手机,但有些智能手机无法正常工作:(
答案 0 :(得分:1)
请use SQLiteAssetHelper
,而不是推出自己的资产包数据库逻辑。
但是,让我们暂时假装洛杉矶市被一些超级恶棍挟持,除非你实施自己的资产包数据库代码,否则这座城市将会被遗忘。而且,让我们进一步假装你喜欢洛杉矶。
在这种情况下,您需要解决两个问题。
首先,替换:
String outFileName = Environment.getDataDirectory() + "/data/"+context.getPackageName()+"/databases/"+ DB_NAME+".sqlite";
使用:
File outFile=myContext.getDatabasePath(DB_NAME+".sqlite");
outFile.getParentFile().mkdirs();
这不仅消除了字符串连接(您正在做出一些假设),但它也适用于辅助用户帐户(您的代码可能不会,因为getDataDirectory()
的行为没有记录)。它也更短。 mkdirs()
调用只是确保在继续之前该目录存在。
第二,改变:
myOutput.flush();
myOutput.close();
为:
myOutput.flush();
myOutput.getFD().sync();
myOutput.close();
这可确保在继续之前将所有内容写入磁盘。 flush()
只是将字节从VM移出到操作系统,但操作系统会执行自己的文件系统级写缓存。 sync()
告诉操作系统将所有内容写入磁盘。如果您有C / C ++背景,sync()
会调用POSIX fsync()
。
这些问题可能会导致您遇到的错误。可能还有其他原因,所以我不能保证这些会彻底解决问题。
(另外,除非您的数据库非常小,否则我会将byte[]
增加到8KB或16KB左右,以提高性能。但是,这不太可能导致您的错误。 )
答案 1 :(得分:0)
几乎所有设备都将目录指定为:
Environment.getDataDirectory()+ “/data/"+context.getPackageName()+"/databases/"+ DB_NAME +”。sqlite“;
但是我们应该检查它是否存在(目录)。 因此,首先检查该目录是否存在,如果该目录不存在,请创建目录。代码如下:
String dir="/data/"+context.getPackageName()+"/databases/";
File file = new File(dir);
if(file.exists()==false){
//directory does not exist
boolean result = file.mkdirs();
}else{
//file is exist
}