Android SQLiteDiskIOException:磁盘I/O错误(代码3850)
我在某些设备上遇到上述错误(非常罕见,到目前为止只有2次): 我的代码中的第115行如下所示:Android SQLiteDiskIOException:磁盘I/O错误(代码3850),android,sqlite,android-sqlite,Android,Sqlite,Android Sqlite,我在某些设备上遇到上述错误(非常罕见,到目前为止只有2次): 我的代码中的第115行如下所示: // here the exception occurs SQLiteDatabase db = SQLiteDatabase.openDatabase(pathApp, null, SQLiteDatabase.OPEN_READONLY); // ... db.close(); 故事 我所做的是: 应用程序具有根权限 它将数据库从另一个应用程序复制到自己的目录中 它试图打开此数据库并读取一些
// here the exception occurs
SQLiteDatabase db = SQLiteDatabase.openDatabase(pathApp, null, SQLiteDatabase.OPEN_READONLY);
// ...
db.close();
故事
我所做的是:
- 应用程序具有根权限
- 它将数据库从另一个应用程序复制到自己的目录中
- 它试图打开此数据库并读取一些数据
- 它会再次关闭文件
public static List<String> readCSVData(String pathDatabase, String tableName) throws InterruptedException, TimeoutException, RootDeniedException, IOException
{
List<String> res = null;
List<String> csvData = null;
final String[] architectures = new String[]{
"armv7",
"armv7-pie",
"armv6",
"armv6-nofpu"
};
for (int i = 0; i < architectures.length; i++)
{
res = readDatabase(architectures[i], pathDatabase, tableName, rootMethod);
if (res.toString().contains("[error:"))
{
L.d(RootNetworkUtil.class, "Trial and Error - ERROR: " + architectures[i]);
}
else
{
int maxLength = (res.toString().length() < 100) ? res.toString().length() : 100;
L.d(RootNetworkUtil.class, "Trial and Error - RESULT: " + res.toString().substring(0, maxLength));
L.d(RootNetworkUtil.class, "Architecture found via trial and error: " + architectures[i]);
csvData = res;
break;
}
}
return csvData;
}
private static List<String> readDatabase(String architecture, String pathDB, String tablename) throws InterruptedException, TimeoutException, RootDeniedException, IOException {
String sqlite = "sqlite3." + architecture;
String pathSQLite3 = getSQLitePath(architecture, tablename);
// OWN class, just copy the file from the assets to the sqlite3 path!!!
AssetUtil.copyAsset(sqlite, pathSQLite3);
String[] cmd = new String[]{
"su\n",
//"chown root.root " + pathSQLite3 + "\n",
"chmod 777 " + pathSQLite3 + "\n",
pathSQLite3 + " " + pathDB + " \".dump '" + tablename + "'\"\n"
};
List<String> res = new ArrayList<>();
List<String> temp = RootUtils.execute(cmd);
for (int i = 0; i < temp.size(); i++)
{
// Fehlerzeilen behalten!!!
if (temp.get(i).contains("error:"))
res.add(temp.get(i));
else if (temp.get(i).startsWith("INSERT INTO \"" + tablename + "\""))
res.add(temp.get(i).replace("INSERT INTO \"" + tablename + "\" VALUES(", "").replace(");", ""));
}
return res;
}
public static String getSQLitePath(String architecture, String addon)
{
String sqlite = "sqlite3." + architecture;
String pathSQLite3 = "/data/data/" + MainApp.get().getPackageName() + "/files/" + sqlite + addon;
return pathSQLite3;
}
- 这两个设备是一个OnePlus2
- 一个人告诉我,问题发生在更新到氧气2.1之后
我的建议是不要在应用程序中打开多个数据库实例,或者在再次打开数据库之前先尝试关闭数据库(可能是您的复制方法没有关闭数据库,或者正在使用同一数据库的另一个实例)。以下是可行的解决方案(已经在生产中测试了2个月左右)这也适用于OnePlus2和Android 6:
- 将
二进制文件添加到您的应用程序中(可在此处找到:)。只需将它们放入您的应用程序资产文件夹中sqlite
// here the exception occurs
SQLiteDatabase db = SQLiteDatabase.openDatabase(pathApp, null, SQLiteDatabase.OPEN_READONLY);
// ...
db.close();
- 找出哪个二进制文件在工作。我尝试了几种方法(例如,通过调用
),但找不到可靠的解决方案,因此我通过以下反复试验来实现:/proc/cpuinfo
- 首先,我将二进制文件从我的资产文件夹复制到我的应用程序
文件夹文件
- 然后我尝试通过
转储所需的数据库并读取结果\.dump'\n
- 我检查结果,如果它包含
我知道二进制文件不工作,如果它以错误:
插入
开始,我知道它工作
- 我用我的二进制文件重复这个过程,直到找到一个可用的二进制文件
- 首先,我将二进制文件从我的资产文件夹复制到我的应用程序
- 然后我就看了结果。结果将包含错误或类似内容。我要么处理错误,要么通过
,以便以行将每一行转换为有效的csv。replace(“插入\”+tablename+“\”值(“,”)。replace(“);”,”)
格式获取内容。我使用opencsv的csv
解析数据,然后CSVReader
public static List<String> readCSVData(String pathDatabase, String tableName) throws InterruptedException, TimeoutException, RootDeniedException, IOException
{
List<String> res = null;
List<String> csvData = null;
final String[] architectures = new String[]{
"armv7",
"armv7-pie",
"armv6",
"armv6-nofpu"
};
for (int i = 0; i < architectures.length; i++)
{
res = readDatabase(architectures[i], pathDatabase, tableName, rootMethod);
if (res.toString().contains("[error:"))
{
L.d(RootNetworkUtil.class, "Trial and Error - ERROR: " + architectures[i]);
}
else
{
int maxLength = (res.toString().length() < 100) ? res.toString().length() : 100;
L.d(RootNetworkUtil.class, "Trial and Error - RESULT: " + res.toString().substring(0, maxLength));
L.d(RootNetworkUtil.class, "Architecture found via trial and error: " + architectures[i]);
csvData = res;
break;
}
}
return csvData;
}
private static List<String> readDatabase(String architecture, String pathDB, String tablename) throws InterruptedException, TimeoutException, RootDeniedException, IOException {
String sqlite = "sqlite3." + architecture;
String pathSQLite3 = getSQLitePath(architecture, tablename);
// OWN class, just copy the file from the assets to the sqlite3 path!!!
AssetUtil.copyAsset(sqlite, pathSQLite3);
String[] cmd = new String[]{
"su\n",
//"chown root.root " + pathSQLite3 + "\n",
"chmod 777 " + pathSQLite3 + "\n",
pathSQLite3 + " " + pathDB + " \".dump '" + tablename + "'\"\n"
};
List<String> res = new ArrayList<>();
List<String> temp = RootUtils.execute(cmd);
for (int i = 0; i < temp.size(); i++)
{
// Fehlerzeilen behalten!!!
if (temp.get(i).contains("error:"))
res.add(temp.get(i));
else if (temp.get(i).startsWith("INSERT INTO \"" + tablename + "\""))
res.add(temp.get(i).replace("INSERT INTO \"" + tablename + "\" VALUES(", "").replace(");", ""));
}
return res;
}
public static String getSQLitePath(String architecture, String addon)
{
String sqlite = "sqlite3." + architecture;
String pathSQLite3 = "/data/data/" + MainApp.get().getPackageName() + "/files/" + sqlite + addon;
return pathSQLite3;
}
publicstaticlist readCSVData(stringpathdatabase,stringtablename)抛出InterruptedException、TimeoutException、RootDeniedException、IOException
{
列表res=null;
列表csvData=null;
最终字符串[]体系结构=新字符串[]{
“armv7”,
“armv7派”,
“armv6”,
“armv6 nofpu”
};
for(int i=0;i
在开发过程中遇到了这种情况。当手机电池耗尽并关机时,它会触发。大概,发生这种情况时,你只需要抓取数据库锁。我突然感到