【问题标题】:Downloading and restore of sqlite database stored in google drive app folder下载和恢复存储在 google drive app 文件夹中的 sqlite 数据库
【发布时间】:2018-01-19 13:22:01
【问题描述】:

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

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

【问题讨论】:

    标签: android android-sqlite fileoutputstream google-drive-android-api android-external-storage


    【解决方案1】:

    我没有使用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");
                        }
    

    这解决了我的问题。

    【讨论】:

      【解决方案2】:

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

      但是canWrite 可以返回 false 的原因有很多,所以你应该检查状态(可能在你尝试 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 = "\r\n";
      
          /**
           * 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 + "\n\t" + 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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多