0

我正在尝试在Android 5.0及以上版本的SD卡中创建一个新文件。所以首先我让用户通过SAF授予权限。这是我如何检查所选目录是否为SD卡。使用DocumentFile.createFile()在SD卡中创建新文件时出错。

public static boolean wrong_directory_selected(Uri uri, Context con) 
    { 

     final File uri_path=new File(FileUtil.getFullPathFromTreeUri(uri,con)); 
     if(uri_path.getName().toLowerCase().equals(new File("SD CARD PATH").getName().toLowerCase())) 
     { 

      return false; 
     } 
     return true; 
    } 

然后这就是我试图创建一个新的文件。

DocumentFile move = DocumentFile(new File("path)).createFile(mime,"name); // But I am getting java.lang.NullPointerException 

下面是我用来获取文件必须创建到的目录的DocumentFile的方法。

public static DocumentFile DocumentFile(final File file) 
{ 

    DocumentFile rootDocFile = DocumentFile.fromTreeUri(con, permission().getUri()); 

    String[] parts = (file.getPath()).split("\\/"); 

    for (int i = 3; i < parts.length; i++) 
    { 

     rootDocFile = rootDocFile.findFile(parts[i]); 

    } 
    return rootDocFile; 
} 

public static UriPermission permission() 
{ 
    for (UriPermission permissionUri : con.getContentResolver().getPersistedUriPermissions()) 
    { 
     final File uri_path = new File(FileUtil.getFullPathFromTreeUri(permissionUri.getUri(), con)); 

     if (uri_path.getName().toLowerCase().equals(new File("SD_CARD_PATH").getName().toLowerCase())) 
     { 
      return permissionUri; 

     } 

    } 

    return null; 
} 

该代码大部分时间工作正常,但有时我得到java.lang.NullPointerException

任何帮助将不胜感激。

编辑:这是我FileUtil类

public final class FileUtil { 


    private static final String PRIMARY_VOLUME_NAME = "primary"; 




    @Nullable 
    public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) 
    { 
     if (treeUri == null) 
     { 
      return null; 
     } 
     String volumePath = FileUtil.getVolumePath(FileUtil.getVolumeIdFromTreeUri(treeUri),con); 
     if (volumePath == null) 
     { 
      return File.separator; 
     } 
     if (volumePath.endsWith(File.separator)) 
     { 
      volumePath = volumePath.substring(0, volumePath.length() - 1); 
     } 

     String documentPath = FileUtil.getDocumentPathFromTreeUri(treeUri); 
     if (documentPath.endsWith(File.separator)) 
     { 
      documentPath = documentPath.substring(0, documentPath.length() - 1); 
     } 

     if (documentPath.length() > 0) 
     { 
      if (documentPath.startsWith(File.separator)) 
      { 
       return volumePath + documentPath; 
      } 
      else { 
       return volumePath + File.separator + documentPath; 
      } 
     } 
     else 
     { 
      return volumePath; 
     } 
    } 


    private static String getVolumePath(final String volumeId, Context con) 
    { 
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) 
     { 
      return null; 
     } 

     try { 
      StorageManager mStorageManager = 
        (StorageManager) con.getSystemService(Context.STORAGE_SERVICE); 

      Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume"); 

      Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList"); 
      Method getUuid = storageVolumeClazz.getMethod("getUuid"); 
      Method getPath = storageVolumeClazz.getMethod("getPath"); 
      Method isPrimary = storageVolumeClazz.getMethod("isPrimary"); 
      Object result = getVolumeList.invoke(mStorageManager); 

      final int length = Array.getLength(result); 
      for (int i = 0; i < length; i++) 
      { 
       Object storageVolumeElement = Array.get(result, i); 
       String uuid = (String) getUuid.invoke(storageVolumeElement); 
       Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement); 

       // primary volume? 
       if (primary && PRIMARY_VOLUME_NAME.equals(volumeId)) 
       { 
        return (String) getPath.invoke(storageVolumeElement); 
       } 

       // other volumes? 
       if (uuid != null) 
       { 
        if (uuid.equals(volumeId)) 
        { 
         return (String) getPath.invoke(storageVolumeElement); 
        } 
       } 
      } 

      // not found. 
      return null; 
     } 
     catch (Exception ex) 
     { 
      return null; 
     } 
    } 

    @TargetApi(Build.VERSION_CODES.LOLLIPOP) 
    private static String getVolumeIdFromTreeUri(final Uri treeUri) 
    { 
     final String docId = DocumentsContract.getTreeDocumentId(treeUri); 
     final String[] split = docId.split(":"); 

     if (split.length > 0) 
     { 
      return split[0]; 
     } 
     else 
     { 
      return null; 
     } 
    } 


    @TargetApi(Build.VERSION_CODES.LOLLIPOP) 
    private static String getDocumentPathFromTreeUri(final Uri treeUri) 
    { 
     final String docId = DocumentsContract.getTreeDocumentId(treeUri); 
     final String[] split = docId.split(":"); 
     if ((split.length >= 2) && (split[1] != null)) 
     { 
      return split[1]; 
     } 
     else 
     { 
      return File.separator; 
     } 
    } 


} 

编辑2:

在该文件已被创建的路径是不错,我也检查了权限URI和即使这不是null。

值是

该文件必须是created-路径/storage/external_SD

权限URI-content://com.android.externalstorage.documents/tree/6634-3765%3A

编辑3:

我用这library找到SD卡路径。

+0

我不知道'FileUtil'是,它比其他的车,因为你不能从一个'Uri'得到'File'(除了创建一个文件并将'Uri'标识的内容复制到文件中,我怀疑FileUtil正在做什么)。 – CommonsWare

+0

@CommonsWare我编辑了这个问题,并添加了我的'FileUtil'类,你可以请看看。 – Rahulrr2602

+2

您正在对Android操作系统版本之间可能会改变的Android实施做出各种假设,包括设备制造商和自定义ROM开发人员所做的更改。 – CommonsWare

回答

0

现在从this答案继续,你有DocumentFile(这是建立在它里面的文件的目录)通过循环只是用myDocumentFile.createFile(...)到您想要的directory创建一个新的文件。

// creating the file 
DocumentFile documentFileNewFile = documentFileGoal.createFile(myMimeType, 
myNewFileName); 

然后通过检查rootDocFile在每次循环中值流归这

outputStream = getContentResolver().openOutputStream(documentFileNewFile.getUri()); 
inputStream = new FileInputStream(myInputFile); 

... 
    if (outputStream != null) { 
     byte[] buffer = new byte[1024]; 
     int read; 
     while ((read = inputStream.read(buffer)) != -1) { 
      outputStream.write(buffer, 0, read); 
     } 
     } 
... 
... 
... 
} finally { 
     if (inputStream != null) 
      inputStream.close(); 
     if (outputStream != null) { 
      outputStream.flush(); 
      outputStream.close(); 
      } 
     } 

Edite
防止findFile上一个空DocumentFile。 (发生在当用户选择了一个错误的路径,而不是sd-card

for (int i = 3; i < parts.length; i++) 
{ 
    if (rootDocFile != null) { 
     rootDocFile = rootDocFile.findFile(parts[i]); 
    } 
} 
+0

请解释你为什么拒绝投票。我会尽我所能去帮助:) – Eftekhari

+0

我在创建新文件时得到了'java.lang.NullPointerException'。我认为'DocumentFile'方法返回null,这意味着我错了某个地方,因为DocumentFile为null。 – Rahulrr2602

+0

如果你想在'sd-card'上创建一个新文件,你需要提供你想要的目录路径。这样你有一个'DocumanetFile'是一个目录。然后在里面创建你的文件。 – Eftekhari