下载和恢复存储在谷歌驱动器应用程序文件夹中的sqlite数据库



我有一个数据库备份存储在驱动器的应用程序文件夹中。下面是我编写的代码。

public void startRestore(View view)
    {
        int EXTERNAL_WRITE_PERMISSION = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.M)
        {
            if(EXTERNAL_WRITE_PERMISSION != PackageManager.PERMISSION_GRANTED)
            {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE))
                {
                    Snackbar.make(mLayout, "Write permission is required",
                            Snackbar.LENGTH_INDEFINITE).setAction("OK", new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // Request the permission
                            ActivityCompat.requestPermissions(BackupActivity.this,
                                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                    PERMISSION_REQUEST_STORAGE);
                        }
                    }).show();
                } else {
                    ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                            PERMISSION_REQUEST_STORAGE);
                }
            }
        }
        if (backupExists())
        {
            Log.d("RESTORE: ", "Started restore");
            final  String driveFileID = sharedPreferences.getString("dbBackupDriveFileID", "");
            final DriveFile driveFile = DriveId.decodeFromString(driveFileID).asDriveFile();
            Log.d("RESTORE_FileID: ", driveFileID);

            final Task<DriveContents> openFileTask = mDriveResourceClient.openFile(driveFile, DriveFile.MODE_READ_ONLY);
            openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>()
            {
                @Override
                public Task<Void> then(@NonNull Task<DriveContents> task) throws Exception
                {
                    Log.d("RESTORE: ", "open File task");
                    DriveContents driveContents = task.getResult();
                    //TODO download file an add to database
                    InputStream inputStream = driveContents.getInputStream();
                    byte[] buf = new byte[8192];
                    int c = 0;

String baseDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                        String fileName = DatabaseHelper.DATABASE_NAME;
                        Log.d("RESTORE: ", baseDir + "/" +fileName);

                        File f = new File(baseDir+File.pathSeparator+fileName);
                        if(f.canWrite())
                        {
                            Log.d("RESTORE: ", "File writable");
                            OutputStream outputStream = new FileOutputStream(f);
                            while ((c = inputStream.read(buf, 0, buf.length)) > 0)
                            {
                                outputStream.write(buf, 0, c);
                                outputStream.flush();
                            }
                            outputStream.close();
                        }
                        else
                        {
                            Log.d("RESTORE: ", "File not writable");
                        }
                    return mDriveResourceClient.discardContents(driveContents);
                }
            })
            .addOnFailureListener(new OnFailureListener()
            {
                @Override
                public void onFailure(@NonNull Exception e)
                {
                }
            });

        }
        else
        {
            Toast.makeText(this, "Backup does not exists", Toast.LENGTH_SHORT).show();
        }
    }

在上面的代码中,控件始终达到 Log.d("RESTORE: ", "File not writable"); 。我具有清单中定义的写入权限,并且还授予了运行时权限。日志中也没有错误。

以下是备份功能供参考。

public void startBackup(View view)
    {
        final ProgressDialog progressDialog = new ProgressDialog(this);
        final File currentDB = this.getDatabasePath(DatabaseHelper.DATABASE_NAME);
        Log.d("DATABASE: ", currentDB.getAbsolutePath());
        Log.d("DATABASE: ", currentDB.getName());
        progressDialog.setMessage("Backing Up!!!!");
        progressDialog.show();
        final Task<DriveFolder> appFolderTask = mDriveResourceClient.getAppFolder();
        final Task<DriveContents> createContentsTask = mDriveResourceClient.createContents();
        Tasks.whenAll(appFolderTask, createContentsTask)
                .continueWithTask(new Continuation<Void, Task<DriveFile>>()
                                  {
                                      @Override
                                      public Task<DriveFile> then(@NonNull Task<Void> task) throws Exception
                                      {
                                          DriveFolder parent = appFolderTask.getResult();
                                          DriveContents contents = createContentsTask.getResult();
                                          InputStream inputStream = null;
                                          try
                                          {
                                              inputStream = new FileInputStream(currentDB);
                                          }
                                          catch (FileNotFoundException e)
                                          {
                                              e.printStackTrace();
                                          }
                                          OutputStream outputStream = contents.getOutputStream();
                                          int c = 0;
                                          byte[] buf = new byte[8192];
                                          if (inputStream != null)
                                          {
                                              while ((c = inputStream.read(buf, 0, buf.length)) > 0)
                                              {
                                                  outputStream.write(buf, 0, c);
                                                  outputStream.flush();
                                              }
                                              outputStream.close();
                                          }
                                          else
                                          {
                                              Toast.makeText(BackupActivity.this, "Some error occurred", Toast.LENGTH_SHORT).show();
                                          }
                                          MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                                                  .setMimeType("application/x-sqlite3")
                                                  .setTitle(currentDB.getName())
                                                  .build();

                                          return mDriveResourceClient.createFile(parent, changeSet, contents);
                                      }
                                  })
                .addOnSuccessListener(this, new OnSuccessListener<DriveFile>() {
                    @Override
                    public void onSuccess(DriveFile driveFile)
                    {
                        progressDialog.dismiss();
                        String driveFileID = driveFile.getDriveId().encodeToString();
                        String dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());
                        SharedPreferences.Editor editor = sharedPreferences.edit();
                        editor.putString("dbBackupDriveFileID", driveFileID);
                        editor.putString("lastDbBackupTime", dateTime);
                        editor.apply();
                        Log.d("DRIVE_FILE", driveFileID);
                        String d = getString(R.string.last_backup) + dateTime;
                        textView.setText(d);
                        Toast.makeText(BackupActivity.this, "Backup Successful. File "+driveFile.getDriveId()
                                .encodeToString(), Toast.LENGTH_LONG).show();
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e)
                    {
                        progressDialog.dismiss();
                        Log.e("DRIVE ", "Unable to create file", e);
                        Toast.makeText(BackupActivity.this, "Unable to backup", Toast.LENGTH_SHORT).show();
                    }
                });
    }

我没有使用File f = new File(baseDir+File.pathSeparator+fileName);,而是将文件用法替换为FileOutputStream。修改部分恢复功能:

DriveContents driveContents = task.getResult();
                    //TODO download file an add to database
                    InputStream inputStream = driveContents.getInputStream();
                    byte[] buf = new byte[8192];
                    int c = 0;
                    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                    {
                        Log.d("RESTORE: ", "External DIR mounted");
                        String baseDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                        String fileName = DatabaseHelper.DATABASE_NAME;

                        String fileFullName = baseDir + File.separator + fileName;
                        Log.d("RESTORE: ", fileFullName);

                                FileOutputStream outputStream;
                                outputStream = new FileOutputStream(fileFullName, false);
                                while ((c = inputStream.read(buf, 0, buf.length)) > 0) {
                                    outputStream.write(buf, 0, c);
                                    outputStream.flush();
                                }
                                outputStream.close();
                    }
                    else
                    {
                        Log.d("RESTORE: ", "External DIR not mounted");
                    }

这解决了我的问题。

答案可以很简单,只需在File f = new File(baseDir+File.pathSeparator+fileName);之后和if(f.canWrite())之前立即添加f.mkdirs()

但是,canWrite可以返回 false 的原因有很多,所以你应该检查 STATE(可能在你尝试之前canWrite

(

就个人而言,我使用以下相当冗长的代码:-

class StoreData {
    private String directory; //Note built internally and includes subdirectory
    private String subdirectory;
    private String filename;
    private boolean mounted;
    private boolean inerror;
    private boolean fileexists;
    private boolean direxists;
    private long errorcode;
    private ArrayList<String> errorlist = new ArrayList<>();
    private ArrayList<File> otherfilesindirectory = new ArrayList<>();
    // Need to be aware of the API
    @SuppressWarnings("unused")
    public static final int API_VERSION = Build.VERSION.SDK_INT;
    private static final long UNMOUNTED = 1;
    private static final long FILEIOERR = 2;
    private static final long READERR = 4;
    private static final String NEWLINE = "rn";
    /**
     * Sole Constructor for a StoreData object
     * Note instantiating creates but the deletes a file, assuming that
     * no prior errors left the instance in an unusable state (as initially set)
     * Note instantiating, if existcheck (3rd param) is true, does not create
     * and delete the file, rather it checks that the file exists
     *     typically for reading an existing file.
     *
     * @param subdirectory - Sub directory in which to create file
     * @param filename - the file name where actual data will be stored
     * @param existcheck - whether or not to check for the existence of the file
     *
     *  Note!! existcheck, if true, will not try to create the file
     */
    public StoreData(String subdirectory, @SuppressWarnings("SameParameterValue") String filename, boolean existcheck) {
        fileexists = false;
        direxists = false;
        mounted = false;
        inerror = false;
        errorcode = 0;
        this.directory = "";
        this.subdirectory = subdirectory;
        this.filename = filename;
        // External Storage must be mounted.
        String chkmnt = Environment.getExternalStorageState();
        if(!(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))) {
            switch (Environment.getExternalStorageState()) {
                case Environment.MEDIA_SHARED : {
                    errorlist.add(
                            "Although External Storage is present." +
                                    " It cannot be used as it's in use via USB." +
                                    "nDisconnect the USB cable and then try again."
                    );
                    break;
                }
                case Environment.MEDIA_REMOVED : {
                    errorlist.add(
                            "External Storage is not present." +
                                    "nInsert an SD Card."
                    );
                    break;
                }
                case Environment.MEDIA_EJECTING : {
                    errorlist.add(
                            "External Storage is being ejected." +
                                    "nRe-insert the SD Card."
                    );
                    break;
                }
                case Environment.MEDIA_NOFS : {
                    errorlist.add(
                            "External Storage is blank or does not have the correct" +
                                    " filesystem present." +
                                    "nUse a valid SDCard."
                    );
                    break;
                }
                case Environment.MEDIA_BAD_REMOVAL : {
                    errorlist.add(
                            "External Storage was removed incorrectly." +
                                    "nRe-insert the SD Card, if this fails then" +
                                    " try restarting the device."
                    );
                    break;
                }
                case Environment.MEDIA_CHECKING : {
                    errorlist.add(
                            "External Storage is unavailable as it is being checked." +
                                    "nTry again."
                    );
                }
                case Environment.MEDIA_MOUNTED_READ_ONLY : {
                    errorlist.add(
                            "External Storage is READ ONLY." +
                                    "nInsert an SD card that is not protected."
                    );
                }
                case Environment.MEDIA_UNKNOWN : {
                    errorlist.add(
                            "External Storage state is UNKNOWN." +
                                    "ntry a different SD Card."
                    );
                }
                case Environment.MEDIA_UNMOUNTABLE : {
                    errorlist.add(
                            "External Storage cannot be mounted." +
                                    "nTry re-inserting the SD Card or using a different SD Card."
                    );
                }
                case Environment.MEDIA_UNMOUNTED : {
                    errorlist.add(
                            "External Storage is not mounted." +
                                    "nTry re-inserting the SD Card or using a different SD Card."
                    );
                }
                default: {
                    errorlist.add(
                            "Undefined Error"
                    );
                }
            }
            this.errorcode = UNMOUNTED;
            return;
        } else {
            this.mounted = true;
        }
        // Get the required directory and specified sub directory
        File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),subdirectory);
        this.directory = dir.getPath();
        // If existcheck is true check that the directories exist
        if (existcheck && dir.exists()) {
            direxists = true;
        }
        // If the directories do not exist try to create them and redo check
        // Note! existcheck is more for file level so always try to create
        // directories
        else {
            boolean x = dir.mkdirs();
            if(dir.exists()) {
                direxists = true;
            }
        }
        if(direxists) {
            refreshOtherFilesInDirectory();
        }
        // File level
        File f = new File(directory,filename);
        // Check if the file exists if requested and return if it does
        if (existcheck) {
            if (f.exists()) {
                fileexists = true;
            }
            return;
        }
        try {
            boolean x = f.createNewFile();
        }
        catch (IOException e) {
            e.printStackTrace();
            this.errorcode = FILEIOERR ;
            errorlist.add(
                    "File Error " + e.getMessage()
            );
            return;
        }
        boolean x = f.delete();
    }
    @SuppressWarnings({"ConstantConditions", "UnusedReturnValue"})
    public boolean refreshOtherFilesInDirectory() {
        boolean rv = true;
        File dir = new File(directory);
        File[] dirlist = dir.listFiles();
        if((dirlist.length) > 0) {
            // Sort the list
            Arrays.sort(dirlist, new Comparator<File>() {
                @Override
                public int compare(File object1, File object2) {
                    return object1.getName().compareTo(object2.getName());
                }
            });
            otherfilesindirectory.clear();
            for (File aDirlist : dirlist) {
                if (!(aDirlist.getName().equals(this.filename))) {
                    otherfilesindirectory.add(aDirlist);
                }
            }
        }
        return rv;
    }
    /**
     * writeData - Write data to the file from String Arraylist passed
     * Note!! a linefeed is added to each string
     * @param datatowrite - strng ArrayList holding data to write
     * @return result flag
     */
    @SuppressWarnings("unused")
    public boolean writeData(ArrayList<String> datatowrite) {
        // Check that this instance is OK
        if (!this.isOK()) {
            this.errorlist.add(
                    "nError prior to call to writeData method."
            );
            return false;
        }
        // Prepare to write
        this.errorlist.clear();
        File f = new File(this.directory,File.separator + this.filename);
        try {
            boolean x =  f.createNewFile();
            FileOutputStream fos = new FileOutputStream(f);
            OutputStreamWriter osw = new OutputStreamWriter(fos);
            for (int i = 0; i < datatowrite.size(); i++) {
                osw.write(datatowrite.get(i) + NEWLINE);
            }
            osw.flush();
            osw.close();
            fos.flush();
            fos.close();
            this.fileexists = true;
        }
        catch (IOException e) {
            e.printStackTrace();
            this.errorcode = FILEIOERR;
            errorlist.add(
                    "File Error " + e.getMessage()
            );
            return false;
        }
        return true;
    }
    /**
     * readData - Populate a String ArrayList from the data in the file
     * Note! Assumes linefeeds in the file separate strings of data
     * @return - result flag
     */
    @SuppressWarnings("unused")
    public ArrayList<String> readData() {
        ArrayList<String> rv = new ArrayList<>();
        if(!this.isOKandExists()) {
            this.errorlist.add(
                    "nError prior to call to readData method or the file doesn't exist."
            );
            this.errorcode = READERR;
            return rv;
        }
        this.errorlist.clear();
        File f = new File(this.directory,File.separator + this.filename);
        try {
            FileInputStream fis = new FileInputStream(f);
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while((line = br.readLine()) != null) {
                rv.add(line);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
            this.errorcode = READERR;
            errorlist.add(
                    "File Read Error" + e.getMessage()
            );
            return rv;
        }
        return rv;
    }
    /**
     * isOK - Check if object is usable
     * @return true if OK else false
     */
    public boolean isOK() {
        return !(errorcode != 0 || !mounted || inerror);
    }
    /**
     * exists = Check if the file exists
     * @return - Result of check
     */
    @SuppressWarnings("unused")
    public boolean exists() {
        return this.fileexists;
    }
    public boolean isOKandExists() {
        return this.isOK() && this.fileexists;
    }
    /**
     * Return a string displaying the instances details
     * @return string displaying object's members
     */
    public String Display() {
        String rv;
        rv = "Directory path=" + directory + "n" +
                "SubDirectory=" + subdirectory + "n" +
                "Filename=" + filename + "n" +
                "Mounted =" + Boolean.toString(mounted) + "n" +
                "Directory Exists=" + Boolean.toString(this.direxists) + "n" +
                "File Exists=" + Boolean.toString(this.fileexists) + "n" +
                "In Error=" + Boolean.toString(inerror) + "n" +
                "Last Error Code=" + Long.toString(errorcode);
        return rv;
    }
    @SuppressWarnings("unused")
    public String DisplayWithOtherFiles() {
        String rv;
        rv = this.Display() + "nOther Files in Directory (" + this.directory + ") ";
        for(int i = 0; i < otherfilesindirectory.size(); i++) {
            rv = rv + "nt" + otherfilesindirectory.get(i).getName();
        }
        return rv;
    }
    /**
     * Retrieve generated error messages. if any
     * @return sting comprised of all error messages generated
     */
    @SuppressWarnings("unused")
    public String getErrorMessages() {
        String rv = "";
        for(int i = 0; i < errorlist.size(); i++) {
            rv = rv + errorlist.get(i);
        }
        return rv;
    }
    /**
     * Method: getDirectory - get the backup directory as a String
     * @return Directory as a String
     */
    public String getDirectory() {
        return this.directory;
    }
    /**
     * Method: getFilename - get the filename of the object as a String
     * @return Filename as a String
     */
    @SuppressWarnings("unused")
    public String getFilename() {
        return this.filename;
    }
    /**
     * Method: getSubDirectory - get the sub-directory as a string
     * @return Sub-Directory as a String
     */
    @SuppressWarnings("unused")
    public String getSubDirectory() {
        return this.subdirectory;
    }
    /**
     * Method: getFilesInDirectory - return an ArrayList of type File
     * @return List of files in the directory as an ArrayList<File>
     */
    public ArrayList<File> getFilesInDirectory() {
        return this.otherfilesindirectory;
    }
}

相关内容

最新更新