访问sqlite时出现Android错误

时间:2015-10-17 11:56:49

标签: android database sqlite copy

我发布了一个有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();
}

我感到困惑,因为它适用于所有智能手机,但有些智能手机无法正常工作:(

2 个答案:

答案 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
 }