使用选择器从外部存储加载文件

4
所以,我正在尝试加载一个简单的 .txt 文件,如下所示:
    private void showFileChooser() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("text/plain");
    intent.addCategory(Intent.CATEGORY_OPENABLE);

    try {
        startActivityForResult(
                Intent.createChooser(intent, "Select a File to Upload"),
                FILE_SELECT_CODE);
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(this, "Please install a File Manager.",
                Toast.LENGTH_SHORT).show();
    }
}

当然,像这样捕获结果:
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case FILE_SELECT_CODE:
            if (resultCode == RESULT_OK) {

                // Get the Uri of the selected file
                Uri uri = data.getData();

它在genymotion上运行良好,并且在我使用已安装的文件浏览器(File explorer,参见上图)时,在我的设备上也很好用。但是,如果像这样直接使用选择器:

enter image description here

它会显示找不到指定的文件。(FileNotFoundException)

现在,我意识到从这两个文件选择器获得的URI是不同的。

content://com.android.externalstorage.documents/document/primary%3ADownload%2Ffile.txt <- 这个不起作用(Android内置浏览器)

content://media/external/file/44751 <- 这个可以用(自定义浏览器)

有没有人知道为什么我获取了相同文件的不同URI?

编辑: 我尝试使用内容解析器从URI获取文件路径,像这样:

public class Utils {

public static String getRealPathFromURI(Context context, Uri contentUri) {
    Cursor cursor = null;
    try {
        String[] proj = {MediaStore.Files.FileColumns.DATA};
        cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(proj[0]);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

仍然没有好运气 :(


哦,我以前也遇到过同样的问题。 也许这个答案可以帮到你。 https://dev59.com/t2Ij5IYBdhLWcg3w04bd祝你好运。 - Konifar
2个回答

2
@CommonsWare的答案可能是解决这个问题的正确方法,但我不确定如何实现他的解决方案。最终我做了@Paul Burke在这个链接上推荐的方法: Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT 编辑
对于我的特定情况,这就是我的代码最终的样子。我留下这个作为未来参考。(我使用了@CommonsWare的解释),请参见他上面的答案。
               try {
                    InputStream inputStream = getContentResolver().openInputStream(uri);
                    BufferedReader br = null;
                    if (inputStream != null) {
                        br = new BufferedReader(new InputStreamReader(inputStream));

                        String line;
                        while ((line = br.readLine()) != null) {
                            text.append(line);
                            text.append("\n");
                        }
                    } else {
                        subscriber.onError(new InputException("There's something seriously wrong with this file"));
                    }

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

1
我曾尝试使用内容解析器来获取URI的文件路径,但是找不到文件路径。Uri并不一定指向您可以在本地文件系统中访问的文件,就像此Web页面的URL也不一定指向您可以在本地文件系统中访问的文件一样。 Uri 可能会表示:

  • 其他应用程序内部存储中保存的文件
  • 数据库中的BLOB列值
  • “云端”中保存的文件,在请求时下载
  • 等等。
使用ContentResolveropenInputStream()等方法读取表示Uri的内容,就像使用HttpUrlConnection读取此Web页面的URL所表示的内容一样。 openInputStream()Uri作为参数并返回一个InputStream。您可以像使用任何其他InputStream(例如FileInputStream、从HttpUrlConnection获取的InputStream)一样使用该InputStream。具体的机制将取决于底层数据(例如读取字符串,将其传递给BitmapFactory以解码Bitmap)。

@feresr:你问题的编辑部分就是问题所在。去掉 getRealPathFromURI()。使用 ContentResolveropenInputStream() 来读取由 Uri 表示的内容。 - CommonsWare
哦,谢谢。让我试试,我会回复你的 :) - frankelot
或者,反过来尝试:尝试在Uri上打开流,如果失败了,那么看看_DATA模式是否起作用。您有如何执行此操作的示例吗?(在Uri上打开流) - frankelot
@feresr:"在 Uri 上打开一个流" - 正如我之前两次所写,并且现在将其加粗以帮助阅读,使用 ContentResolveropenInputStream() 读取由 Uri 表示的内容。你知道如何获取 ContentResolver,因为它在你问题的代码中。openInputStream() 接受一个参数:要打开的 Uri。你会得到一个 InputStream,就像你通过 HttpUrlConnection 从 Web 服务器读取数据或者通过 FileInputStream 从本地文件读取数据时一样。 - CommonsWare
@feresr:我增加了更多的清晰度,包括一个流行的SO问题的链接,该问题涉及从“InputStream”中读取文本。 - CommonsWare
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接