当前位置: 首页 > 知识库问答 >
问题:

Uri方案“文件”麻烦:获取文件大小,在外部查看器中打开PDF,并打开输入流(与方案“内容”相比)?

林烨烨
2023-03-14

当我在我的应用程序中打开PDF时,提供的uri可以有2种方案:“文件”和“内容”:

> < li>

使用Dropbox:file:///data/data/com . Dropbox . Android/global/external/doc previews/test 2 . pdf

使用谷歌驱动:内容://媒体/外部/文件/142

有了“内容”,我所有的功能都按预期工作,但有了“文件”,我遇到了一些麻烦:

    < li >我不知道如何获取PDF的文件大小。 < li >在外部PDF查看器中打开PDF会导致类似“无法打开文件”的错误(无论这是dropbox、Google Drive还是任何其他应用程序)。 < li >打开inputstream(将PDF转换为byte[])也会导致问题:FileNotFoundException。

一个可能的解决方案是将“文件”转换为“内容”,那么我会很高兴。我已经寻找了一段时间,但无法找到如何,所以我想这是不可能的。那么如何解决这3个问题呢?

我的AndroidManifest:

<activity android:name=".activities.PdfActivity"
....
  <intent-filter android:label="Open PDF">
    <action android:name="android.intent.action.SEND"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="application/pdf"/>
  </intent-filter>
</activity>

在Pdfactive中,我收集Uri:

uri = intent.getParcelableExtra(Intent.EXTRA_STREAM)

1)然后获取文件大小:

switch (uri.getScheme()) {
  case "file":
    // How to get the filesize here?
     break;
  case "content":
    // Get filesize using cursor
    Cursor cursor = getContentResolver().query(uri, new String[]{MediaColumns.SIZE}, null, null, null);
    cursor.moveToFirst();
    size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaColumns.SIZE));
    cursor.close();
    break;
}

2) 使用以下代码在外部查看器中打开PDF:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

try {
  startActivity(intent);
} catch (ActivityNotFoundException e) {
  // Show dialog: no PDF viewer on device
}

3) 使用输入流将 PDF 转换为字节 []:

public byte[] getByteArrayFromPdf(Uri uri) throws IOException {
    InputStream inputStream = null;
    try {
        switch (uri.getScheme()) {
          case "file":
            // How to do this?
            break;
          case "content":
            inputStream = getContentResolver().openInputStream(uri);
            break;
          default:
            // Something going wrong...
        }
        return getByteArrayUsingInputStream(inputStream);
    } finally {
        if (inputStream != null) {
            inputStream.close();
        }
    }
}

编辑:我的文件保存在下载文件夹中(因此内容uri来自Google Drive)。

getContentResolver().openInputStream(uri) 导致方案“file”的 FileNotFoundException。即使两个 uri 方案都源自同一文件。这意味着 FileNotFoundException 应该由不存在的文件以外的其他内容产生。

显然,它是由libcore.io.ErrnoException引起的:打开失败:EACCES(权限拒绝),当我查看Dropbox中的uri(文件)时,这更有意义:出现dropbox打开文件并将其保存在com.dropbox.android中,我无权访问。我想这解释了所有的麻烦,我说得对吗?

最终编辑:如上所述,Dropbox PDF viewer应用程序生成的文件可能存在隐私问题,因为使用Adobe(和其他应用程序,也会生成带有“文件”的uri),我没有任何问题:新文件(uri.getPath())。length()给出了文件大小,接收inputstream的工作原理与“content”uri的工作原理相同。

但这给了我一个新的问题:我是否可以:使用Dropbox应用程序打开一个外部PDF文件(如下载地图),“发送PDF”在我的应用程序中打开它,然后以某种方式访问该文件,这样我就可以读取大小,在另一个PDF查看器中打开,并将其转换为inputstream?

ps.以这种方式在我的应用程序中打开PDF时,是否可以使用其他uri方案?

共有1个答案

祝俊雄
2023-03-14

我不知道如何获得PDF的文件大小

Uri上调用getPath()。将该路径包装在File对象中,并在File对象上调用long()

或者,将您现有的代码替换为DocumentFile。将fromSingleUri()用于内容方案,将fromFile()用于file方案。然后,在DocumentFile上调用getSize()

在外部PDF查看器中打开PDF会导致“无法打开文件”等错误(无论这是dropbox、Google Drive还是任何其他应用程序)。

另一个应用程序对该内容没有权限。您可以尝试通过将< code > FLAG _ GRANT _ READ _ URI _ PERMISSION 添加到< code>Intent来转移权限。

打开输入流(将PDF转换为字节[])也会导致问题:FileNotFoundException。

您没有显示给出这个异常的代码。< code>openInputStream()支持< code >文件和< code >内容方案,因此这两种情况都要使用。

 类似资料:
  • 我使用以下代码存储pdf文件: 之后在onActivityResultIm使用OutputStream保存数据。Uri到文件可以看起来像: 但当我试图以此目的启动活动时,pdf viewer应用程序显示错误: 是否可以从内容Uri打开pdf查看器活动?

  • 打开文件 哈,现在你已经在无意间学会了一种在 Vim 中打开文件的方式,虽然这种方式并不是最常用的,但却是最 直接的,尤其是当你的代码中 include 了某文件时,下面介绍另外两种常用的打开方式。 在 Vim 中打开文件 :e <filename> 打开名为 filename 的文件,若文件不存在则创建之 :Ex 在 Vim 中打开目录树,光标选中后回车打开对应文件(提示:- 进入上级目录) 查

  • 问题内容: 我得到一个例外:“ URI方案不是文件” 我正在做的是尝试获取文件名,然后将该文件(从另一个服务器)从servlet中保存到我的计算机/服务器上。 我有一个名为“ url”的字符串,从这里开始是我的代码: 导致错误的行是这一行: 我添加了其余的代码,以便您可以看到我正在尝试执行的操作。 问题答案: URI“ scheme”是位于“:”前面的内容 错误消息告诉您仅适用于“文件:” URI

  • 我在寻求帮助。我已经创建了一个应用程序,其中一个按钮是用来打开特定文件的。 我已将指定的.txt文档放入程序的文件夹中。它与“解决方案”文件处于同一级别。现在,如何编写打开这个特定的。txt文件的代码?

  • 问题内容: 我做了以下工作; 这在Mac OS中触发,但在Windows中不触发。在Windows中还有其他事件或其他方式可以执行此操作吗? 问题答案: 这是仅Mac功能。最接近的替代方法是app.makeSingleInstance(callback)。 您可以安排使用url作为参数启动应用程序:myApp my-scheme:// stuff 然后,无论首先启动哪个应用程序进程,都使用url进

  • 问题内容: 我知道我们应该在问题中添加一些代码,但是我非常傻眼,无法束手无策,也找不到任何可循的例子。 基本上,我想打开文件 C:\ A.txt ,其中已经包含内容,并在末尾写一个字符串。基本上是这样的。 文件A.txt包含: 我想打开它并在末尾写Sue,所以文件现在包含: 抱歉,没有代码示例,今天早上我的大脑死了。 问题答案: 请搜索Larry Page和Sergey Brin向全世界发布的Go