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