我可以编写存储在外部SDCARD上的SQLite DB吗?SOS



env desc: Android版本:6.0.1, DB由客户创建并存储在外部存储上,完成任务后,SQLite DB的数据将收集。

我们需要读并编写每个不同服务逻辑的DB。

问题:

 Could not open the database in read/write mode. 
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=10, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.example.xx.sqlitedemo/com.example.xx.sqlitedemo.MainActivity}: 
android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.

代码:

SQLiteDatabase.openOrCreateDatabase

请求权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

在调试模式下以下面的代码检查DB文件:

 new File(dbpath).exists();

dbpath是:

"/storage/4B53-98D9/System/System.db"

动态权限已经存在,问题仍然存在。

androidmanifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xx.sqlitedemo">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

mainActivity.java

package com.example.xx.sqlitedemo;
import android.Manifest;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.DatabaseErrorHandler;
import android.database.DefaultDatabaseErrorHandler;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteCursorDriver;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQuery;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
public class MainActivity extends AppCompatActivity {
    private static final int EXTERNAL_STORAGE_REQ_CODE = 10;
    private static final int MOUNT_UNMOUNT_FILESYSTEMS = 20;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        requestMountPermission();
        requestStoragePermission();
        int o = 0;
    }

    private void requestMountPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)) {
                Toast.makeText(this, "please give me the permission", Toast.LENGTH_SHORT).show();
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS},
                        MOUNT_UNMOUNT_FILESYSTEMS);
            }
        } else {
            requestStoragePermission();
            int i = 1;
        }
    }
    public void requestStoragePermission() {
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                Toast.makeText(this, "please give me the permission", Toast.LENGTH_SHORT).show();
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        EXTERNAL_STORAGE_REQ_CODE);
            }
        } else {
            openSQLiteDataBase();
            int i = 1;
        }
    }
    private void openSQLiteDataBase() {
        //            SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase("/storage/4B53-98D9/System/System.db", new CustomCursorFactory(), new CustomDbErrorHandler());
        DatabaseHelper helper = new DatabaseHelper(this,"System.db");
        SQLiteDatabase database = helper.getReadableDatabase();
        int ii = 0;
        Cursor cursor = database.query(null,null,null,null,null,null,null,null);
        database.close();
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case EXTERNAL_STORAGE_REQ_CODE:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    openSQLiteDataBase();
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
            break;
            case MOUNT_UNMOUNT_FILESYSTEMS:
                break;
        }
    }
    class CustomCursorFactory implements SQLiteDatabase.CursorFactory {
        @Override
        public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) {
            if (Build.VERSION.SDK_INT < 11) {
                return new SQLiteCursor(db, masterQuery, editTable, query);
            } else {
                return new SQLiteCursor(masterQuery, editTable, query);
            }
        }
    }
    class CustomDbErrorHandler implements DatabaseErrorHandler {
        DefaultDatabaseErrorHandler __d = new DefaultDatabaseErrorHandler();
        boolean __once = false;
        @Override
        public void onCorruption(SQLiteDatabase dbObj) {
            if (__once) {
                throw new SQLiteDatabaseCorruptException("db corrupted and cannot be recovered");
            }
            __once = true;
            __d.onCorruption(dbObj);
        }
    }
    class DatabaseContext extends ContextWrapper {
        private static final String DEBUG_CONTEXT = "DatabaseContext";
        public DatabaseContext(Context base) {
            super(base);
        }
        @Override
        public File getDatabasePath(String name)  {
            File sdcard = Environment.getExternalStorageDirectory();
            String path = this.getFilesDir().getAbsolutePath();
            String dbfile = "/storage/4B53-98D9/System/System.db";  //sdcard.getAbsolutePath() + File.separator+ "databases" + File.separator + name;
            if (!dbfile.endsWith(".db")) {
                dbfile += ".db" ;
            }
            File result = new File(dbfile);
            if (!result.getParentFile().exists()) {
                result.getParentFile().mkdirs();
            }
            return result;
        }
        /* this version is called for android devices >= api-11. thank to @damccull for fixing this. */
        @Override
        public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
            return openOrCreateDatabase(name,mode, factory);
        }
        /* this version is called for android devices < api-11 */
        @Override
        public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
            SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
            // SQLiteDatabase result = super.openOrCreateDatabase(name, mode, factory);
                Log.w(DEBUG_CONTEXT, "openOrCreateDatabase(" + name + ",,) = " + result.getPath());
            return result;
        }
    }
    public class DatabaseHelper extends SQLiteOpenHelper {
        private static final int DATABASE_VERSION = 1;
        DatabaseHelper(final Context context, String databaseName)  {
            super(new DatabaseContext(context), databaseName, null, DATABASE_VERSION);
        }
        @Override
        public void onCreate(SQLiteDatabase db) {
        }
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}

在2017-03-05更新:@GreenApps提供的方式很危险:

Have a look at getExternalFilesDirs(). Look at the second item returned.
That would then look like "/storage/4B53-98D9/Android/data/<package>/files/System.db".

卸载应用程序时,同时删除了数据。

/storage/4B53-98D9/Android/data/<package> was deleted.

有人可以回答我的问题吗?

预先感谢!

仅读取SD卡,这就是为什么您会收到无法在写模式下打开的消息。

您可以尝试将DB文件放在SD卡上可以写入的SD卡上的特定目录中。

查看getExternalFilesdirs()。查看返回的第二个项目。

然后看起来像"/storage/4B53-98D9/Android/data/<package>/files/System.db"

用于请求权限,请尝试以下代码。

//check for WRITE_EXTERNAL_STORAGE permission
        int hasAccessExternalStoragePermission = ContextCompat.checkSelfPermission(LoginActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (hasAccessExternalStoragePermission != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(LoginActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_CODE_ASK_PERMISSIONS);
    }

并像以下内容一样处理它。

@Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_PERMISSIONS:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.e(TAG, "Permission Granted....");
                    createFile();
                }else{
                     Log.e(TAG, "Permission Not Granted....");
                }
        }
    }

我猜问题即将到来,因为您正在使用shouldShowRequestPermissionRationale此方法。如果此处使用此方法,请阅读用法。

最新更新