-1

I am writing this cause I had enough....

I could not take it anymore...

I read & read & read...& then, read a little more...just like before I wrote this question here!

I am trying to copy a ready made sqlite DB from assets to app DB folder.

I have tried all combinations of copying code, path code & more.

This is from SO:

        /**
         * http://stackoverflow.com/questions/10738623/copy-database-from-assets-folder-in-unrooted-device
         * Copies your database from your local assets-folder to the just created
         * empty database in the system folder, from where it can be accessed and
         * handled. This is done by transfering bytestream.
         * */
        public static void copyDataBase(String dbname, Context mContxt) throws IOException {

            myContext = mContxt;
            // Open your local db as the input stream
            InputStream myInput = myContext.getAssets().open(dbname);
            // Path to the just created empty db
//          String outFileName = "/data/data/" + MainActivity.PACKAGE_NAME + "/databases/" + dbname;
            String outFileName1 = "/data/data/" + MainActivity.PACKAGE_NAME; // + "/databases/" + dbname;
            String outFileName = myContext.getFilesDir().getAbsolutePath().replace("files", "databases/"); // + "/Database/";

            File newDir = null;

            File dir = new File(myContext.getApplicationInfo().dataDir+"/databases");
            dir.mkdirs();

            if (!dir.isDirectory()) {
                Log.v(TAG, "NOTaDIrectory");
                newDir = new File(outFileName);
                newDir.mkdir();
                if(newDir.exists()) {
                    if (newDir.isDirectory()) {
                        Log.v("isDIrectory", newDir.toString());
                    }
                }
            } else {
                Log.v(TAG, "NOTaDIrectory");
            }

            File outFileName1Dir = new File(outFileName1);

            if (!outFileName1Dir.isDirectory()) {
                newDir = new File(outFileName);
                newDir.mkdir();
                if(newDir.exists()) {
                    if (newDir.isDirectory()) {
                        Log.v("isDIrectory", newDir.toString());
                    }
                }
            } else {
                Log.v(TAG, "ISaDIrectory");
            }
            Log.v(TAG, outFileName + dbname);
            File file = new File(outFileName + dbname);
//          File file = myContext.getFileStreamPath(dbname);
            Log.v(TAG, "" + file.getPath() + " - " + file.getTotalSpace());
            Log.v(TAG, outFileName + dbname);

            File ff = new File(outFileName , dbname);
            if (ff.exists()) {
                Log.v(TAG, "FF -----------EXISTS");
            }

            String[] files = myContext.fileList();
            for (String file1 : files) {
                Log.v(TAG, file1.toString());
                if (file1.equals(dbname)) {
                    Log.v(TAG, "FILE EXISTS");
                }
            }

            if (file.exists()) {
                Log.v(TAG, "FILE EXISTS");
                if(file.isFile()) {
                    Log.v(TAG, "isFILE");
    //               return;
                }
            } else {
                Log.v(TAG, "NO FILE");
                // 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);
                    Log.v(TAG, "Copying DB");
                }
                Log.v("FileExists", "" + file.createNewFile());
                Log.v("FileWriteAble", "" + file.canWrite());
                // Close the streams
                myOutput.flush();
                myOutput.close();
                myInput.close();
                if (!file.canWrite()) {
                    Log.v("FileExists", "" + file.setWritable(true));
                }
                Log.v(TAG, "" + file.getPath() + " - " + file.getTotalSpace());
            }
        }

I know...its a bunch of code but some people would ask to see it....

JUST CANT SEEM TO WRAP MY HEAD AROUND THE PROBLEM.

Some basic code from MainActivity that call this function:

public class MainActivity extends FragmentActivity {

    Context myContext;

    String DB_PATH = null;
    String DB_NAME = null;
    public static ContextWrapper cw = null;
    public static String PACKAGE_NAME;

After that, the call and some other defs: **Most of the commented lines were used in different attempts to trying and accomplish this task...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        myContext = getApplicationContext();

//      ContextWrapper 
        cw = new ContextWrapper(getApplicationContext());
//      DB_PATH =cw.getFilesDir().getAbsolutePath()+ "/Database/";

        DB_NAME = "dates1.sqlite";
//      DB_PATH = cw.getFilesDir().getAbsolutePath().replace("files", "Databases/"); // + "/Database/";


/*      DB_PATH = destPath.substring(0, destPath.lastIndexOf("/")) + "/databases";
        Log.v(TAG, DB_PATH);
*/      
//      get package name from anywhere
        PACKAGE_NAME = getApplicationContext().getPackageName();

/*      DbHelperNew dbNew = new DbHelperNew(cw, DB_NAME, null, 1);
        Boolean T = dbNew.checkDataBase();

        Log.v(TAG, T.toString());
*/      
        String[] files = this.fileList();
        for (String file : files) {
            Log.v(TAG, file.toString());
            if (file.equals(DB_NAME)) {
                Log.v(TAG, "FILE EXISTS");
            }
        }

        try {
            DbUtils.copyDataBase(DB_NAME, myContext);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

//      DbUtils.copyDataBase(DB_NAME, DB_PATH, myContext);

/*      File src = new File("file:///android_asset/" + DB_NAME);
        File dest = new File(DB_PATH + DB_NAME);

        DbUtils.movedb(src, dest);
*/      
        for (String file : files) {
            Log.v(TAG + "SECOND", file.toString());
            if (file.equals(DB_NAME)) {
                Log.v(TAG, "FILE EXISTS");
            }
        }
        /* END */
      _dbHelper = new DbHelper(getApplicationContext());
      db = _dbHelper.getReadableDatabase();

I do apologise for the messy code...just to show the different attempts...

ERROR msgs:

09-23 09:21:45.609: V/DbUtils(12851): Copying DB
09-23 09:21:45.621: W/System.err(12851): java.io.IOException: open failed: ENOTDIR (Not a directory)
09-23 09:21:45.628: W/System.err(12851):    at java.io.File.createNewFile(File.java:940)

09-23 09:21:45.640: W/System.err(12851): Caused by: libcore.io.ErrnoException: open failed: ENOTDIR (Not a directory)

09-23 09:21:45.699: E/SQLiteOpenHelper(12851): Couldn't open dates1.sqlite for writing (will try read-only):
09-23 09:21:45.699: E/SQLiteOpenHelper(12851): android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database


09-23 09:21:45.707: E/SQLiteLog(12851): (14) cannot open file at line 30174 of [00bb9c9ce4]
09-23 09:21:45.707: E/SQLiteLog(12851): (14) os_unix.c:30174: (20) open(/data/data/com.ndroidians.listfrag/databases/dates1.sqlite) - 
09-23 09:21:45.710: E/SQLiteDatabase(12851): Failed to open database '/data/data/com.ndroidians.listfrag/databases/dates1.sqlite'.
09-23 09:21:45.710: E/SQLiteDatabase(12851): android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database

In order to solve the different error issues, I did:

  1. Try different directories, inc.: code for different OS vers, different FOLDER/ PACKAGE accessing code, creating the Dir.
  2. Changed file extension from */db to *.sqlite
  3. Changed file permissions to 777 in assets folder
  4. Tried different copy functions
  5. Tried different Phones

I might have forgotten something along the way but it has been 2 long days that I am cracking my head over this simple (seemingly) task...

HELP....

EDIT

Some more info:

I have trid to chown as suggested...still got the same error:

Emulator (this time)

>= 4.2 API17
New database is being copied to device! dates1.sqlite
New database has been copied to device!
chown 10054:10054 /data/data/com.ndroidians.listfrag/databases/dates1.sqlite
AFTER PROCESS
(14) cannot open file at line 30176 of [00bb9c9ce4]
(14) os_unix.c:30176: (20) open(/data/data/com.ndroidians.listfrag/databases/dates1.sqlite) - 
Failed to open database '/data/data/com.ndroidians.listfrag/databases/dates1.sqlite'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database

The funny thing about it is that on Emulator it shows that the databases folder is not a folder but kind of a file... I attach a picture....Emulator_File_Explorer

On the other hand on a device its show Data as correct size in App Info. I attach a screen capture.... Nexus S OS-4.1.2_ScreenCaptuer_App_Info

This is a riddle....anyone???

Jadeye
  • 3,551
  • 4
  • 47
  • 63

3 Answers3

0

As mentioned at this SO post of sqlitelog,

Problem is with the location of the db for different version of SDK.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
sjain
  • 23,126
  • 28
  • 107
  • 185
  • I have tried this! #1 - "code for different OS vers"...: if(android.os.Build.VERSION.SDK_INT >= 4.2){ DB_PATH = context.getApplicationInfo().dataDir + "/databases/"; } else { DB_PATH = "/data/data/" + context.getPackageName() + "/databases/"; } – Jadeye Sep 23 '13 at 08:46
  • FYI: the code you referred to yields the same result: /data/data/PACKAGE_NAME/databases/ – Jadeye Sep 23 '13 at 11:13
0

Check file/group ownership properties and make sure they are assigned to your app. If they aren't, you can do this by executing the chown [your app's UID] : [your app's UID] /[PATH TO YOUR DATABASE FILE] at run time with the Runtime.getRuntime().exec(commandLine) method. This (along with setting permissions) solved the same problem I was having. (May or may not require root access, I can't remember off the top of my head).

String filesdir = [PATH TO DB FILE];
String theFile = [YOUR DB FILE];
PackageManager pm = ctx.getPackageManager();
ApplicationInfo ai;

ai = pm.getApplicationInfo(ctx.getPackageName(), 0);
Integer uid = ai.uid;
String newo = String.valueOf(uid) + ":" + String.valueOf(uid);
String newocmd = "chown " + newo + " " + filesdir + theFile;

try{
     Process process;            
     process = Runtime.getRuntime().exec(newocmd);
     BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
    }
    catch (InterruptedException e) 
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
}
Di Vero Labs
  • 344
  • 1
  • 4
0

This is from a working project of mine If you face any problem further you can ask for help

The Database is a sqlite Database in assets with

.db

extension From Activity

    private SQLiteDatabase sqlitedb;
DatabaseHandler db;
private static final String DB_NAME = "UQDB.db";
SharedPreferences mPrefs;

public boolean getFirstRun() {
    return mPrefs.getBoolean("firstRun", true);
}

public void setRunned() {
    SharedPreferences.Editor edit = mPrefs.edit();
    edit.putBoolean("firstRun", false);
    edit.commit();
}


public void firstRunPreferences() {
    Context mContext = this.getApplicationContext();
    mPrefs = mContext.getSharedPreferences("UltimateQuotes", 0); // 0 = mode
    // private:
    // only this app can
    // read these preferences
}


    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_uq);
    setBackGround();

    firstRunPreferences();

    db = DatabaseHandler.getInstance(this, DB_NAME);
            if (getFirstRun()) {
                sqlitedb = db.getDatabase();

                setAlarm();

                //db.updateQuotesRating(quotesList);                    
                Log.d("After loading ","Quotes Loaded from Server");

                setRunned();

                //db.updateCategories(categoriesList);
                //db.updateQuotesRating(quotesList);

            } 
            else {
                sqlitedb = db.getWritableDatabase();



            }
     }

From DBHandler

    private static String DB_PATH_PREFIX = "/data/data/";
private static String DB_PATH_SUFFIX = "/databases/";

private static void initialize(Context context, String databaseName) {
    if (instance == null) {
        /**
         * Try to check if there is an Original copy of DB in asset
         * Directory
         */
        if (!checkDatabase(context, databaseName)) {
            // if not exists, I try to copy from asset dir
            try {
                copyDataBase(context, databaseName);
            } catch (IOException e) {
                Log.e(TAG,"Database "+ databaseName
                        + " does not exists and there is no Original Version in Asset dir");
            }
        }

        Log.i(TAG, "Try to create instance of database (" + databaseName
                + ")");
        instance = new DatabaseHandler(context, databaseName,null, DATABASE_VERSION);
        sqliteDb = instance.getWritableDatabase();
        Log.i(TAG, "instance of database (" + databaseName + ") created !");
    }
}

/***
 * Static method for getting singleton instance
 * 
 * @param context
 *            : application context
 * @param databaseName
 *            : database name
 * @return : singleton instance
 */
public static final DatabaseHandler getInstance(
        Context context, String databaseName) {
    initialize(context, databaseName);
    return instance;
}

/***
 * Method to get database instance
 * 
 * @return database instance
 */
public SQLiteDatabase getDatabase() {
    return sqliteDb;
}




     /***
 * Method for Copy the database from asset directory to application's data
 * directory
 * 
 * @param databaseName
 *            : database name
 * @throws IOException
 *             : exception if file does not exists
 */

private void copyDataBase(String databaseName) throws IOException {
    copyDataBase(context, databaseName);
}

/***
 * Static method for copy the database from asset directory to application's
 * data directory
 * 
 * @param aContext
 *            : application context
 * @param databaseName
 *            : database name
 * @throws IOException
 *             : exception if file does not exists
 */
private static void copyDataBase(Context aContext, String databaseName)
        throws IOException {

    // Open your local db as the input stream
    InputStream myInput = aContext.getAssets().open(databaseName);

    // Path to the just created empty db
    String outFileName = getDatabasePath(aContext, databaseName);

    Log.i(TAG, "Check if create dir : " + DB_PATH_PREFIX
            + aContext.getPackageName() + DB_PATH_SUFFIX);

    // if the path does not exist first, create it
    File f = new File(DB_PATH_PREFIX + aContext.getPackageName()
            + DB_PATH_SUFFIX);
    if (!f.exists())
        f.mkdir();

    Log.i(TAG, "Trying to copy local DB to : " + outFileName);

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

    Log.i(TAG, "DB (" + databaseName + ") copied!");
}

/***
 * Method to check if database exists in application's data directory
 * 
 * @param databaseName
 *            : database name
 * @return : boolean (true if exists)
 */
public boolean checkDatabase(String databaseName) {
    return checkDatabase(context, databaseName);
}

/***
 * Static Method to check if database exists in application's data directory
 * 
 * @param aContext
 *            : application context
 * @param databaseName
 *            : database name
 * @return : boolean (true if exists)
 */
public static boolean checkDatabase(Context aContext, String databaseName) {
    SQLiteDatabase checkDB = null;

    try {
        String myPath = getDatabasePath(aContext, databaseName);

        Log.i(TAG, "Trying to conntect to : " + myPath);
        checkDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);
        Log.i(TAG, "Database " + databaseName + " found!");
        checkDB.close();
    } catch (SQLiteException e) {
        Log.i(TAG, "Database " + databaseName + " does not exists!");

    }

    return checkDB != null ? true : false;
}

/***
 * Method that returns database path in the application's data directory
 * 
 * @param databaseName
 *            : database name
 * @return : complete path
 */
private String getDatabasePath(String databaseName) {
    return getDatabasePath(context, databaseName);
}

/***
 * Static Method that returns database path in the application's data
 * directory
 * 
 * @param aContext
 *            : application context
 * @param databaseName
 *            : database name
 * @return : complete path
 */
private static String getDatabasePath(Context aContext, String databaseName) {
    return DB_PATH_PREFIX + aContext.getPackageName() + DB_PATH_SUFFIX
            + databaseName;
}
Rajnish Mishra
  • 826
  • 5
  • 21
  • what are DB_PATH_PREFIX, DB_PATH_SUFFIX???, & where is "the just created empty db" created??? Thank you kindly. – Jadeye Sep 23 '13 at 14:39
  • I have updated the code these are two string declared in DBHandler to match the location of db file on device or AVD file system. private static String DB_PATH_PREFIX = "/data/data/"; private static String DB_PATH_SUFFIX = "/databases/"; – Rajnish Mishra Sep 23 '13 at 18:23
  • Thank you, I have realized that and did so...so far your code has been of assistance but I still have this issue with copying to a NEXUS S device. It does copy to the Emulator. strange – Jadeye Sep 24 '13 at 08:46
  • This code is working fine on my Samsung galaxy Grand can you share you log cat or any specific issue. – Rajnish Mishra Sep 24 '13 at 10:03
  • Sorry for the delayed response. I ran it several times:_(1)_ **NEXUS S with OS-4.1.2** _(2)_ **Emulator 2.3.3** _(3)_ **Emulator-Nexus_S-OS-4.1.2**. Results: **(1)** Failed **(2)** Worked like a charm **(3)** Worked Like a charm **LINKS TO LOGS** [first Go:](http://blog.ndroidians.com/wp-content/uploads/2013/09/log.txt), [second_Go:](http://blog.ndroidians.com/wp-content/uploads/2013/09/new_log.txt) – Jadeye Sep 27 '13 at 14:49
  • Can you please share your code... from DbUtils.java and MainActivity.java – Rajnish Mishra Sep 27 '13 at 15:20
  • [MainActivity](http://blog.ndroidians.com/wp-content/uploads/2013/09/MainActivity.txt) - [DbUtils](http://blog.ndroidians.com/class-for-easy-sqlite-database-reference/)...please – Jadeye Sep 29 '13 at 17:45
  • In your dbutils try flushing the outstream before closing it. myOutput.flush(); myOutput.close(); myInput.close(); – Rajnish Mishra Sep 29 '13 at 18:41
  • just put myOutput.flush(); before myOutput.close(); It is recommended that you flush the buffer before closing it. – Rajnish Mishra Oct 04 '13 at 06:44