2016-12-19 5 views
0

Я делаю приложение для Android, которое позволяет передавать некоторые файлы из внутреннего хранилища на внешнее хранилище (SD-карту) с помощью SAF.Как программно перемещать, копировать файлы в SD?

Вот как я называю намерение позволить пользователю выбрать каталог SD-карты.

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); 
     intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
     startActivityForResult(intent, 42); 

И это мой onActivityResult

public void onActivityResult(int requestCode, int resultCode, Intent data) {  
      treeUri = data.getData(); 
     final int takeFlags = data.getFlags() 
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION 
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
      getActivity().getContentResolver().takePersistableUriPermission(treeUri, takeFlags); 

    } 

Я беру разрешение на всю карту SD, так что я могу переместить или удалить любой файл в сд карты в любое время .The проблема заключается, что даже после того, разрешение Я не могу переместить или удалить любой файл на SD-карте.

Как перенести файл из внутреннего хранилища на внешнюю (SD-карту) для Android версии 5.0 и выше.

EDIT: Это код, который я использую для перемещения файлов.

public static void MoveFiles(File src, File dst) throws IOException 
{ 
    FileChannel inChannel = new FileInputStream(src).getChannel(); 
    FileChannel outChannel = new FileOutputStream(dst).getChannel(); 
    try 
    { 
     inChannel.transferTo(0, inChannel.size(), outChannel); 
    } 
    finally 
    { 
     if (inChannel != null) 
      inChannel.close(); 
     if (outChannel != null) 
      outChannel.close(); 
      src.delete(); 

    } 
} 
+0

«Проблема в том, что даже после получения разрешения я не могу перемещать или удалять любые файлы на SD-карте» - вы не указали какой-либо код для «перемещения или удаления любого файла на SD-карте», и у вас нет объяснил, какова фактическая проблема (например, трассировка стека Java). – CommonsWare

+0

у вас есть, конечно, эти разрешения добавлены в файл манифеста? – user1086500

+0

@CommonsWare Я отредактировал мой вопрос. – Rahulrr2602

ответ

2

Вот как я, наконец, решил проблему.

Сначала позвоните пользователю, чтобы предоставить разрешение на запись для всей SD-карты.

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); 
     intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
     startActivityForResult(intent, 42); 

Затем on onActivityResult берет на себя письменное разрешение.

public void onActivityResult(int requestCode, int resultCode, Intent data) {  
      treeUri = data.getData(); 
     final int takeFlags = data.getFlags() 
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION 
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
      getActivity().getContentResolver().takePersistableUriPermission(treeUri, takeFlags); 

    } 

И это код, который я использовал для копирования файлов на SD-карту.

public static boolean copy(File copy, String directory, Context con) { 
    static FileInputStream inStream = null; 
    static OutputStream outStream = null; 
      DocumentFile dir= getDocumentFileIfAllowedToWrite(new File(directory), con); 
      String mime = mime(copy.toURI().toString()); 
      DocumentFile copy1= dir.createFile(mime, copy.getName()); 
      try { 
       inStream = new FileInputStream(copy); 
       outStream = 
         con.getContentResolver().openOutputStream(copy1.getUri()); 
       byte[] buffer = new byte[16384]; 
       int bytesRead; 
       while ((bytesRead = inStream.read(buffer)) != -1) { 
        outStream.write(buffer, 0, bytesRead); 

       } 


      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } finally { 
       try { 

        inStream.close(); 

        outStream.close(); 


        return true; 


       } catch (IOException e) { 
        e.printStackTrace(); 
       } 


      } 

      return false; 
     } 

В приведенном выше коде используются следующие два метода.

getDocumentFileIfAllowedToWrite метод, который возвращает DocumentFile, если разрешено писать.

public static DocumentFile getDocumentFileIfAllowedToWrite(File file, Context con) { 

     List<UriPermission> permissionUris = con.getContentResolver().getPersistedUriPermissions(); 

     for (UriPermission permissionUri : permissionUris) { 

      Uri treeUri = permissionUri.getUri(); 
      DocumentFile rootDocFile = DocumentFile.fromTreeUri(con, treeUri); 
      String rootDocFilePath = FileUtil.getFullPathFromTreeUri(treeUri, con); 

      if (file.getAbsolutePath().startsWith(rootDocFilePath)) { 

       ArrayList<String> pathInRootDocParts = new ArrayList<String>(); 
       while (!rootDocFilePath.equals(file.getAbsolutePath())) { 
        pathInRootDocParts.add(file.getName()); 
        file = file.getParentFile(); 
       } 

       DocumentFile docFile = null; 

       if (pathInRootDocParts.size() == 0) { 
        docFile = DocumentFile.fromTreeUri(con, rootDocFile.getUri()); 
       } else { 
        for (int i = pathInRootDocParts.size() - 1; i >= 0; i--) { 
         if (docFile == null) { 
          docFile = rootDocFile.findFile(pathInRootDocParts.get(i)); 
         } else { 
          docFile = docFile.findFile(pathInRootDocParts.get(i)); 
         } 
        } 
       } 
       if (docFile != null && docFile.canWrite()) { 
        return docFile; 
       } else { 
        return null; 
       } 

      } 
     } 
     return null; 
    } 

И метод mime, который возвращает тип mime файла.

public static String mime(String URI) { 
    static String type; 
      String extention = MimeTypeMap.getFileExtensionFromUrl(URI); 
      if (extention != null) { 
       type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extention); 
      } 
      return type; 
     } 

Я протестировал вышеуказанный код с помощью Android Lollipop и Marshmallow.

+0

Что случилось с вашим другим требованием? удаление исходного файла после копирования? – Theo

+0

Если файл присутствует во внутреннем хранилище, вы можете просто удалить файл с помощью file.delete(); где файл - это файл, который вы хотите удалить. – Rahulrr2602

2

Я беру разрешение на всю карту SD, так что я могу переместить или удалить любой файл в сд карты в любое время

Нет, вы не являетесь. Вы принимаете разрешение на любое дерево документов, которое пользователь выбирает, чтобы иметь возможность работать с этим деревом документов с использованием API-интерфейсов платформы хранения (например, DocumentFile).

Проблема заключается в том, что даже после принятия разрешения я не в состоянии переместить или удалить любой файл в SD-карте

Это происходит потому, что вы пытаетесь работать с API файловой системы. У вас нет прав на работу со съемным хранилищем через эти API, за пределами определенных областей, предназначенных для доступа к вашему приложению (например, getExternalFilesDirs()).

Если вы хотите работать с деревом документа:

  • Use DocumentFile.fromTreeUri() создать DocumentFile, указывающий в корне этого дерева

  • Используйте методы на этой DocumentFile, чтобы увидеть, что это то, что уровень дерево, получите DocumentFile объектов на ветвях этого дерева, получите DocumentFile объектов по содержанию в этом дереве и т. д.

+0

Я новичок в разработке Android. У меня есть список файлов, которые нужно перенести на SD-карту. Как я могу получить DocumentFile из файла и как перенести файл документа в любую папку на SD-карте. – Rahulrr2602

+0

@ Rahulrr2602: Используйте 'DocumentFile' методы, такие как' createFile() ', чтобы получить' DocumentFile', где в дереве документов вы хотите добавить некоторый контент. Вызовите 'getUri()' на этом 'DocumentFile', затем передайте это' openOutputStream() 'на' ContentResolver'. Оттуда используйте стандартный ввод/вывод Java (например, откройте «FileInputStream» в исходном файле, затем скопируйте байты из «InputStream» в 'OutputStream'). – CommonsWare

+0

Как создать DocumentFile в любом каталоге или папке на SD-карте. У меня есть только путь к этому каталогу. – Rahulrr2602

Смежные вопросы