【问题标题】:Android - getting from a Uri to an InputStream to a byte array?Android - 从 Uri 到 InputStream 再到字节数组?
【发布时间】: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 类的一个实例

标签: android


【解决方案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,你就不能使用标准的文件阅读器。

        【讨论】:

          猜你喜欢
          • 2021-01-23
          • 2017-09-30
          • 2019-04-14
          • 1970-01-01
          • 2012-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多