DocumentFile.exists() 在尚不存在的路径上始终返回 true,因为 DocumentFile().fromTreeUri()

问题描述 投票:0回答:3

我尝试使用 DocumentFile (由于存储访问框架)在创建文件之前检查文件是否存在。但是

DocumentFile().fromTreeUri()
删除了可能的 Uri 中不存在的部分,这导致
DocumentFile().exists()
始终返回 true,无论它是否存在。

我创建了一个简单的例子来证明我的观点。首先我们要求用户选择一个目录:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // Ask the user for the source folder
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, 100);
}

响应后,我们将

/fictionalFile
添加到路径中(从而使其成为不存在的文件),然后检查它是否存在:

public void onActivityResult(int requestCode, int resultCode, Intent resultData)
{
    if (resultCode == RESULT_OK)
    {
        if(requestCode == 100)
        {
            Uri fictionalURI = Uri.parse(resultData.getData()+"/fictionalFile");
            DocumentFile fictionalFile = DocumentFile.fromTreeUri(this, fictionalURI);
            Log.i("STORAGE", "FICTIONAL URI: "+fictionalURI);
            Log.i("STORAGE", "FICTIONAL DOCUMENTFILE URI: "+fictionalFile.getUri());

            if(fictionalFile.exists())
            {
                Log.i("STORAGE", "Fictional file exists");
            }
        }
    }
}

但是,当在虚构的 Uri 上运行 DocumentFile.fromTreeUri() 时,假的“/fictionalfile”部分会丢失,这会导致 DocumentFile.exists() 函数返回 true,如下面的 LogCat 所示:

I/存储:虚构 URI:content://com.android.externalstorage.documents/tree/17FA-1C18%3AFileSync%2Ftarget/fictionalFile

I/存储:虚构文档文件 URI:content://com.android.externalstorage.documents/tree/17FA-1C18%3AFileSync%2Ftarget/document/17FA-1C18%3AFileSync%2Ftarget

I/STORAGE:虚构文件存在

(在上面的例子中,我使用的是SD卡,因此路径名很长)

是否有另一种方法来检查尚未创建的文档文件是否存在?用例是,当将文件从目录 A 复制到目录 B 时,我想在开始传输之前检查该文件是否已存在于目录 B 中。

更新:我现在意识到使用

DocumentFile.fromTreeUri()
是错误的,我应该使用
DocumentFile.fromSingleUri()
。这有帮助,但在新文件上运行
.exists()
时,我得到
W/DocumentFile: Failed query: java.lang.UnsupportedOperationException: Unsupported Uri content://com.android.externalstorage.documents/tree/17FA-1C18%3AFileSync%2Ftarget/fictionalFile
。有什么想法吗?

public void onActivityResult(int requestCode, int resultCode, Intent resultData)
{
    if (resultCode == RESULT_OK)
    {
        if(requestCode == 100)
        {
            Uri fictionalURI = Uri.parse(resultData.getData()+"/fictionalFile");
            DocumentFile fictionalFile = DocumentFile.fromSingleUri(this, fictionalURI);
            Log.i("STORAGE", "FICTIONAL URI: "+fictionalURI);
            Log.i("STORAGE", "FICTIONAL DOCUMENTFILE URI: "+fictionalFile.getUri());

            if(fictionalFile != null && fictionalFile.exists())
            {
                Log.i("STORAGE", "Fictional file exists");
            }
        }
    }
}
java android uri documentfile
3个回答
6
投票

给定

treeUri
作为
Uri
返回的
ACTION_OPEN_DOCUMENT_TREE
,使用
treeUri
DocumentFile
包装在
fromTreeUri()
中,然后在
findFile()
上调用
DocumentFile
,提供您要查找的显示名称(例如,
fictionalFile
)。如果返回
null
,则没有与该显示名称匹配的文件。

哇:

if (DocumentFile.fromTreeUri(this, treeUri).findFile(whatevs) == null) {
  // TODO: something
}

但请注意,“显示名称”不一定是文件名。


1
投票

就我而言,当我使用 applicationContext 检查 CoroutineWorker 中的

DocumentFile.fromSingleUri(context, media.fileUri)?.exists() == true
时,当从外部应用程序(例如文件管理器)中删除文件时,DocumentProvider 始终返回 true。

问题已解决

uri.isFileExist(context)

import android.content.Context
import android.net.Uri
import androidx.documentfile.provider.DocumentFile

fun DocumentFile?.isFile() = this?.isFile ?: false

fun DocumentFile?.isExists() = this?.exists() ?: false

fun DocumentFile?.getLength() = this?.length() ?: 0

fun DocumentFile?.isFileExist() = isFile() && isExists() && getLength() > 0

fun Uri.isFileExist(context: Context) =
    DocumentFile.fromSingleUri(context, this).isFileExist()

更新: 下面的解决方案可以在 Android 10+ 上正常工作。我最终更换了它以使其在所有版本的 Android 上正常工作。

fun Uri.isFileExist(context: Context): Boolean {
    var isExist = false
    runCatching {
        context.contentResolver.openInputStream(this)?.let {
             it.close()
             isExist = true
        }
    }
    return isExist
}

0
投票

DocumentFile.fromSingleUri
为我工作。但是,如果文件不存在,我想创建一个新文件。

希望这至少能解决您的目的。

Uri fileUri = DocumentsContract.buildDocumentUriUsingTree(Prefs.externalURI, filePath);
if(DocumentFile.fromSingleUri(this, fileUri).exists()) {
  // do some stuff
}
© www.soinside.com 2019 - 2024. All rights reserved.