Android - 从 Uri 到 InputStream 再到字节数组?

Posted

技术标签:

【中文标题】Android - 从 Uri 到 InputStream 再到字节数组?【英文标题】:Android - getting from a Uri to an InputStream to a byte array? 【发布时间】:2011-01-27 00:59:31 【问题描述】:

我正在尝试从 android Uri 获取字节数组。

我有以下代码,但它一直告诉我字节数组是 61 字节长,即使文件很大 - 所以我认为它可能会将 Uri string 变成字节数组,而不是文件:(

  Log.d(LOG_TAG, "fileUriString = " + fileUriString);
  Uri tempuri = Uri.parse(fileUriString);
  InputStream is = cR.openInputStream(tempuri);
  String str=is.toString();
  byte[] b3=str.getBytes();
  Log.d(LOG_TAG, "len of data is " + imageByteArray.length
     + " bytes");

请有人帮我弄清楚该怎么做?

输出为“fileUriString = content://media/external/video/media/53”和“len of data is 61 bytes”。

谢谢!

【问题讨论】:

cR 是什么?你问如何“从 Uri 到 InputStream”,但你已经得到了一个 InputStream,但没有说明你是如何得到它的。 @Vince cR 是 ContentResolver 类的一个实例 【参考方案1】:

is.toString() 将为您提供 InputStream 实例的字符串表示形式,而不是其内容。

您需要从 InputStream 中读取()字节到您的数组中。有两种读取方法可以做到这一点,read() 一次读取一个字节,read(byte[] bytes) 将 InputStream 中的字节读取到您传递给它的字节数组中。


更新:鉴于 InputStream 没有这样的长度,要读取字节,您需要读取字节,直到没有剩余为止。我建议为自己创建一个类似这样的方法是一个不错的简单起点(至少我会在 Java 中这样做)。

public byte[] readBytes(InputStream inputStream) throws IOException 
  // this dynamically extends to take the bytes you read
  ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();

  // this is storage overwritten on each iteration with bytes
  int bufferSize = 1024;
  byte[] buffer = new byte[bufferSize];

  // we need to know how may bytes were read to write them to the byteBuffer
  int len = 0;
  while ((len = inputStream.read(buffer)) != -1) 
    byteBuffer.write(buffer, 0, len);
  

  // and then we can return your byte array.
  return byteBuffer.toByteArray();

【讨论】:

谢谢。但这并不能解决问题,因为我必须在提供 byte[] 数组之前指定它的长度,而我无法从 InputStream 中得到它。知道如何计算给定 Uri 的数据长度吗? 您不必事先知道文件大小。建议的解决方案适用于任何流长度。 为什么我们需要声明一个缓冲区大小?我们可以输入任何长度吗?如果可以,有没有办法一次输入全部内容? @AP257 我不确定它是否有帮助,但要从输入流中读取字节数,您可以调用 .available() 方法【参考方案2】:

使用 Apache Commons,您可以读取 Stream 中的所有字节,这要感谢 IOUtils.toByteArray(InputStream),如下所示:

byte[] recordData = IOUtils.toByteArray(inStream);

下载jar: http://commons.apache.org/io/download_io.cgi

【讨论】:

【参考方案3】:

Kotlin 方式:

@Throws(IOException::class)
private fun readBytes(context: Context, uri: Uri): ByteArray? = 
    context.contentResolver.openInputStream(uri)?.buffered()?.use  it.readBytes() 

在 Kotlin 中,他们为 InputStream 添加了方便的扩展函数,例如 bufferedusereadBytes

buffered 将输入流装饰为 BufferedInputStream use 处理关闭流 readBytes 主要负责读取流并写入字节数组

错误案例:

IOException 可以在过程中发生(就像在 Java 中一样) openInputStream 可以返回null。如果您在 Java 中调用该方法,您可以轻松地监督这一点。考虑一下您想如何处理这种情况。

【讨论】:

【参考方案4】:
while ((len = inputStream.read(buffer)) != -1)

应该是

while (inputStream.available() >0 && (len = inputStream.read(buffer)) != -1)

如this answer 中所述,如果流没有可用字节,这种方式读取不会阻塞。

【讨论】:

如果您只收到了一半文件,则阻止是正确的行为。检查可用性是检查文件结尾的可怕替代方法。【参考方案5】:

使用 Google Guava,您可以使用 ByteStreams.toByteArray(InputStream) 获取输入流中的所有字节:

InputStream is = ...;
byte[] bytes = ByteStream.toByteArray(is);

【讨论】:

【参考方案6】:

分享我的想法:D

private static byte[] getStringFromInputStream(InputStream is) 


    BufferedReader br = null;
    StringBuilder sb = new StringBuilder();
    byte[] bReturn = new byte[0];

    String line;
    try 
    

        br = new BufferedReader(new InputStreamReader(is, "Big5"));
        while ((line = br.readLine()) != null) 
        
            sb.append(line);
        
        String sContent = sb.toString();
        bReturn = sContent.getBytes();          
     
    catch (IOException e) 
    
        e.printStackTrace();
     
    finally 
    
        if (br != null) 
        
            try 
            
                br.close();
             
            catch (IOException e) 
            
                e.printStackTrace();
            
        
     
    return bReturn;

【讨论】:

InputStreamReader 使用 Big5 编码格式,因为我的内容是汉字,所以可以使用 UTF-8【参考方案7】:

如果你有一个 Uri,而不是一个常规的文件名,你应该使用 Content Resolver。 Android: Getting a file URI from a content URI?

我试过了,效果很好。 乌里乌里; // 这是一些东西,我从文件选择器中获得。当然,我必须确定,uri 指向一个文件名,它不是图像、音频或其他东西......

InputStream is=getContentResolver().openInputStream(uri);
InputStreamReader ir=new InputStreamReader(is);
bu=new BufferedReader(ir);
String s;
while ((s=bu.readLine())!=null)
    //do something with the line...

bu.close();

我在代码中省略了一些 try-catch-finally,但最重要的事情都在这里了。 首先,如果你有一个 uri,你就不能使用标准的文件阅读器。

【讨论】:

以上是关于Android - 从 Uri 到 InputStream 再到字节数组?的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 上从照片 URI 创建文件

从 Android 中的 URI 检索联系人电话号码

如何从用户手机获取联系人 URI 并在 android 中使用 glide 加载

Android 获取视频 URI 源

Android - 如何从原始文件中获取 Uri?

Android 从 Intent 获取裁剪图像的 URI