Android “Uri方案”;文件";问题:获取文件大小,在外部查看器中打开PDF,然后打开inputstream(与scheme“content”相比)?

Android “Uri方案”;文件";问题:获取文件大小,在外部查看器中打开PDF,然后打开inputstream(与scheme“content”相比)?,android,pdf,uri,dropbox,url-scheme,Android,Pdf,Uri,Dropbox,Url Scheme,当我在我的应用程序中打开PDF时,提供的uri可以是两种模式:“文件”和“内容”: 使用Dropbox:file:///data/data/com.dropbox.android/global/external/docpreviews/test2.pdf 使用Google Drive:content://media/external/file/142 对于“内容”,我的所有功能都按预期工作,但对于“文件”,我遇到了一些问题: 我不知道如何获得PDF的文件大小 在外部PDF查看器中打开PDF会

当我在我的应用程序中打开PDF时,提供的uri可以是两种模式:“文件”和“内容”:

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

  • 使用Google Drive:content://media/external/file/142

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

  • 我不知道如何获得PDF的文件大小
  • 在外部PDF查看器中打开PDF会导致类似“无法打开文件”的错误(无论这是dropbox、Google Drive还是任何其他应用程序)
  • 打开inputstream(将PDF转换为字节[])也会导致问题:FileNotFoundException
  • 一个可能的解决方案是将“文件”转换为“内容”,然后我会非常高兴。我已经找了一段时间了,但是找不到是怎么回事,所以我想那是不可能的。那么如何解决这三个问题呢

    我的清单:

    <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>
    
    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转换为字节[]:

    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();
            }
        }
    }
    
    编辑:我的文件保存在下载文件夹中(因此是来自Google Drive的内容uri)

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

    显然,这是由libcore.io.ErrnoException:open failed:EACCES(权限被拒绝)引起的,当我从Dropbox查看uri(文件)时,这更有意义:Dropbox似乎会打开文件并将其保存在com.Dropbox.android中,我在其中没有访问权限。我想这解释了所有的麻烦,对吗

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

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

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

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

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

    或者,将现有代码替换为
    DocumentFile
    。对
    内容
    方案使用
    fromsingeluri()
    ,对
    文件
    方案使用
    fromFile()
    。然后,在
    DocumentFile
    上调用
    getSize()

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

    另一个应用对该内容没有权限。您可以尝试通过将
    标志\u授予\u读取\u URI\u权限
    添加到
    意图
    来转移权限

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


    您不显示导致此异常的代码
    openInputStream()
    支持
    file
    content
    方案,因此在这两种情况下都使用该方案。

    不幸的是,没有一种方案有效:1)file.length(),返回0。使用documentFile时,fromSingleUri返回null(我猜您是指documentFile上的.length()而不是size()?)。。。2) 国旗没有什么区别。。。3) 我使用openInputStream来表示“file”,这导致了FileNotFoundException(我澄清了我描述这一点的帖子)。在东方,最后一个解决方案应该是可行的,也许例外给了我们一个提示?也许在那个uri上它真的不存在?嗯,我用两个PDF查看器打开了同一个PDF(一个提供“文件”,另一个提供“内容”),所以这不可能。@PKuijpers:Dropbox提供给你的
    Uri
    是你无法访问的,因为他们的应用程序中有一些bug。“我是否可以……”当然欢迎您在
    上执行
    操作发送
    以接收PDF文件,如果这是您的意思。。。但你已经有了。所以,试试这个流程,看看你从你选择的PDF查看器应用程序中得到了什么。请注意,并非所有PDF查看器都可以提供“共享”选项。“以这种方式在我的应用程序中打开PDF时,是否可以使用其他uri方案?”--当然可以
    http
    https
    android。
    
    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();
            }
        }
    }