SQLiteDiskIOException: disk I/O error when copying database in Android - android

The code for copying database:
public static final String DB_PATH = Environment.getDataDirectory() + "/data/MyPackageName/databases/";
public static final String DB_NAME = "MyDB.sqlite";
private void copyDataBase(String dbPath){
try{
InputStream inputStream = context.getAssets().open(dbName);
OutputStream appDB = new FileOutputStream(dbPath,false);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
appDB.write(buffer, 0, length);
}
appDB.flush();
appDB.close();
inputStream.close();
}catch(IOException e){
e.printStackTrace();
}
}
this code is work fine in every phone and every android version, but i get a SQLiteDiskIOException in some phones (for example Galaxy S Plus) in above code or this line:
SQLiteDatabase db = super.getWritableDatabase();
everyone can help me in this problem?

Thanks my friend,
my problem is solved with using SQLiteAssetHelper introduced in https://github.com/jgilfelt/android-sqlite-asset-helper

Related

Room Database doesn't work after being copied from assets

I'm trying to use a prepopulated database in my Android project. My pipeline is this:
I'm creating a new database and processing a large JSON file to populate it (on Android). It takes a lot of time (~15 minutes or so), so I'd like to pack this created database and distribute it with the app.
I upload the database to Firebase Storage and download it manually on my PC. This database file, when checked with a browser from https://sqlitebrowser.org/, appears correct.
I add the downloaded database to Assets folder, and copy it over to original database path.
The database should work at this point, but it doesn't. There's no error message. It appears empty, but the copied file has proper size and everything. Restarting the app doesn't help, and calling new Room.databaseBuilders doesn't help either.
Code:
Database:
#Database(entities = {...}, version = 1)
public abstract class MyDatabase extends RoomDatabase {
public abstract DbDao dbDao();
private static MyDatabase instance = null;
public static MyDatabase getInstance(Context context) {
if (instance == null){
instance =
Room.databaseBuilder(context, MyDatabase.class, "db")
.build();
}
return instance;
}
Uploading:
public void uploadDB(){
String DBPath = mContext.getDatabasePath("db").getAbsolutePath();
File file = new File(DBPath);
StorageReference storageRef = FirebaseStorage.getInstance().getReference().child("db/my_database.db");
BufferedInputStream bis;
try {
bis = new BufferedInputStream(new FileInputStream(file));
} catch (FileNotFoundException e){
e.printStackTrace();
return;
}
storageRef.putStream(bis);
}
Copying:
public void loadDbFromAssets() throws IOException {
InputStream in = mContext.getAssets().open("databases/my_database.db");
String db_path = mContext.getDatabasePath("db").getAbsolutePath();
File out_file = new File(db_path);
if (out_file.exists()){
boolean deleted = out_file.delete();
if (!deleted) {
DebugLog.log("Old DB not deleted!");
return;
}
}
OutputStream out = new FileOutputStream(out_file);
copy(in, out);
File in_file = new File(db_path);
DebugLog.log("Copied file size: " + in_file.length() + "b");
}
public static void copy(InputStream in, OutputStream out) throws IOException{
try {
try {
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) > 0){
out.write(buff, 0, len);
}
} finally {
out.flush();
out.close();
}
} finally {
in.close();
}
}
Am I missing something?
EDIT: Solved using https://github.com/humazed/RoomAsset.

Android - Copy files from assets to /data/data folder

I need to use some files in my app. They are kept in asset folder. I saw discussions on SO, where the files are being copied from asset folder, to /data/data/<package_name> on the internal storage, and then being used.
I get the code, but what I do not get is, what is the need to copy the assets to internal storage?
Try this:(Use all three method its work for me and assign destination path in "toPath" string object)
String toPath = "/data/data/" + getPackageName(); // Your application path
private static boolean copyAssetFolder(AssetManager assetManager,
String fromAssetPath, String toPath) {
try {
String[] files = assetManager.list(fromAssetPath);
new File(toPath).mkdirs();
boolean res = true;
for (String file : files)
if (file.contains("."))
res &= copyAsset(assetManager,
fromAssetPath + "/" + file,
toPath + "/" + file);
else
res &= copyAssetFolder(assetManager,
fromAssetPath + "/" + file,
toPath + "/" + file);
return res;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private static boolean copyAsset(AssetManager assetManager,
String fromAssetPath, String toPath) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(fromAssetPath);
new File(toPath).createNewFile();
out = new FileOutputStream(toPath);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
return true;
} catch(Exception e) {
e.printStackTrace();
return false;
}
}
private static void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
One reason that just popped up for me is when using existing C/C++ code with NDK that requires a path to a file and you don't want to modify that code.
For example, I'm using an existing C library that needs some data files and the only existing interface is some "load( char* path )" function.
Perhaps there is actually some better method but I have not found any yet.
public final String path = "/data/data/com.aliserver.shop/databases/";
public final String Name = "store_db";
public void _copydatabase() throws IOException {
OutputStream myOutput = new FileOutputStream(path + Name);
byte[] buffer = new byte[1024];
int length;
InputStream myInput = MyContext.getAssets().open("store_db");
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myInput.close();
myOutput.flush();
myOutput.close();
}
I think you can't edit/modify data in asset folder in run time or after application installed .So we move files into internal folder then start working on it.

How to read preexisting database into Android using ORMLite

I want to use preexisting database file using ORMLite in android. I have database.db file of already creted database. I want to use it in my app.
My class extends OrmLiteSqliteOpenHelper.
Can any one have an idea? Please help
I use to copy database file into data path using
public static void copyDataBase(String path,Context c) throws IOException{
//Open your local db as the input stream
InputStream myInput = c.getAssets().open("Mydb.db");
// Path to the just created empty db
String outFileName = "/data/data/packageName/databases/databaseName";
String outFileName2 = "/data/data/packageName/databases/";
File file = new File(outFileName2);
if(!file.exists())
file.mkdirs();
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//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();
myOutput.close();
myInput.close();
}
But it wont help me .
This is kind of a stab in the dark since I do not know what your exact problem is, but can't you just specify the database file (and path) in the OrmLiteSqliteOpenHelper constructor?
OrmLiteSqliteOpenHelper(android.content.Context context, String databaseName, android.database.sqlite.SQLiteDatabase.CursorFactory factory, int databaseVersion)
Also there are a number of questions on this forum that deal with opening custom database files. This question is not ORMLite specific but they might get you forward since it open a custom database file.
Hope this help you a bit on your way.
I have solved the problem by below implementation
try {
String destPath = "/data/data/" + context.getPackageName()
+ "/databases";
Log.v("LOG", destPath);
File f = new File(destPath);
if (!f.exists()) {
f.mkdirs();
File outputFile = new File("/data/data/"
+ context.getPackageName() + "/databases",
"Name ofyour Database");
outputFile.createNewFile();
String DatabaseFile = "database file name from asset folder";
InputStream in = context.getAssets().open(DatabaseFile);
OutputStream out = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
Log.v("TAG", "ioexeption");
e.printStackTrace();
}

Database is shown in emulator but not on my android device

Here is my code...
private static String DB_NAME = "pa1.db";
private static String DB_PATH = "/data/data/in.bitcode.sn/databases/";
private void copyDataBase() throws IOException {
InputStream myInput = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
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();
}
You cannot write to /data folder. This is an Android system folder. It works in the emulator because in the emulator you're root, while you're probably not in your device.
Maybe you want to use Android's integrated backup API instead of this.

how to solve a databse issue in actual android device?

I have created database in my application and stored data in that database now when i run my app in emulater it shows all the data but when i run the same app in my android device it shows the error ?
here is my code.
private static String DB_NAME = "pa1.db";
private static String DB_PATH = "/data/data/in.bitcode.sn/databases/";
private void copyDataBase() throws IOException {
InputStream myInput = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
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();
you should not set the database path fixed but use
context.getDatabasePath(DB_NAME)

Categories

Resources