-1

我写这篇文章是因为我受够了......

我再也受不了了……

我阅读并阅读并阅读......然后,再阅读一点......就像我在这里写这个问题之前一样!

我正在尝试将现成的 sqlite 数据库从资产复制到应用程序数据库文件夹。

我已经尝试了复制代码、路径代码等的所有组合。

这是来自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());
            }
        }

我知道...它是一堆代码,但有些人会要求查看它....

只是似乎无法解决这个问题。

MainActivity 中调用此函数的一些基本代码:

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;

之后,调用和其他一些定义:**大多数注释行用于尝试和完成此任务的不同尝试......

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

我为凌乱的代码道歉......只是为了展示不同的尝试......

错误消息:

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

为了解决不同的错误问题,我做了:

  1. 尝试不同的目录,公司:不同操作系统版本的代码,不同的文件夹/包访问代码,创建目录。
  2. 将文件扩展名从 */db 更改为 *.sqlite
  3. 将 assets 文件夹中的文件权限更改为 777
  4. 尝试了不同的复制功能
  5. 试过不同的手机

我可能在此过程中忘记了一些东西,但我已经花了 2 天的时间来完成这个简单(看似)的任务......

帮助....

编辑

更多信息:

我已经按照建议尝试了 chown ......仍然遇到同样的错误:

模拟器(这次)

>= 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

有趣的是,在模拟器上它显示数据库文件夹不是文件夹,而是一种文件......我附上一张图片......Emulator_File_Explorer

另一方面,在设备上,它在 App Info 中将数据显示为正确的大小。我附上屏幕截图....Nexus S OS-4.1.2_ScreenCaptuer_App_Info

这是个谜……有人吗???

4

3 回答 3

0

检查文件/组所有权属性并确保将它们分配给您的应用程序。如果不是,您可以通过在运行时使用 Runtime.getRuntime().exec(commandLine) 方法执行 chown [your app's UID] : [your app's UID] /[PATH TO YOUR DATABASE FILE] 来做到这一点。这(连同设置权限)解决了我遇到的同样问题。(可能需要也可能不需要root访问权限,我不记得了)。

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();
}
于 2013-09-23T10:33:42.120 回答
0

这是我的一个工作项目如果您遇到任何问题,您可以寻求帮助

数据库是资产中的 sqlite 数据库

。D b

从活动扩展

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



            }
     }

来自 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;
}
于 2013-09-23T13:38:45.290 回答
0

正如在sqlitelog的 SO post 中提到的,

Problem is with the location of the db for different version of SDK.
于 2013-09-23T07:49:44.760 回答