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

时间:2016-10-17 12:37:15

标签: android pdf uri dropbox url-scheme

< 查看以下重要的EDIT >

当我在我的应用程序中打开PDF时,提供的uri可以是2个方案:“file”和“content”:

  • 使用Dropbox: file:///data/data/com.dropbox.android/global/external/docpreviews/test2.pdf

  • 使用Google云端硬盘: content:// media / external / file / 142

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

  1. 我不知道如何获取PDF的文件大小。
  2. 在外部PDF查看器中打开PDF会导致错误,例如“无法打开文件”(无论是Dropbox,Google云端硬盘还是其他任何应用)。
  3. 打开输入流(将PDF转换为byte [])也会造成麻烦:FileNotFoundException。
  4. 一个可能的解决方案是将“文件”转换为“内容”,然后我会非常高兴。我一直在寻找它,但不知道如何,所以我想这是不可能的。那么如何解决这三个问题呢?

    我的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>
    

    在PdfActivity中我收集了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)使用inputstream将PDF转换为byte []:

    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();
            }
        }
    }
    

    EDIT :我的文件保存在downloads文件夹中(因此来自Google云端硬盘的内容为uri)。

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

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

    最终编辑: 如上所述,由Dropbox PDF查看器应用程序制作的文件隐私可能存在问题,因为使用Adobe(和其他应用程序,这也导致带有“文件”的文件)我没有任何麻烦:< em> new File(uri.getPath())。length()给我文件大小,接收输入流与“content”uri相同。

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

    PS。以这种方式在我的应用程序中打开PDF时可能有其他的uri方案吗?

1 个答案:

答案 0 :(得分:0)

  

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

致电getPath()上的Uri。在File对象中换行该路径,然后在length()对象上调用File

或者,用DocumentFile替换现有代码。对fromSingleUri()方案使用contentfromFile()方案使用file。然后,在getSize()上调用DocumentFile

  

在外部PDF查看器中打开PDF会导致错误,例如&#34;无法打开文件&#34; (无论是Dropbox,Google云端硬盘还是其他任何应用)。

其他应用对该内容没有任何权利。您可以通过将FLAG_GRANT_READ_URI_PERMISSION添加到Intent来尝试转移权利。

  

打开输入流(将PDF转换为byte [])也会造成麻烦:FileNotFoundException。

您不会显示提供此异常的代码。 openInputStream()支持filecontent计划,因此请在两种情况下使用它。