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
添加了方便的扩展函数,例如 buffered
、use
和 readBytes
。
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 再到字节数组?的主要内容,如果未能解决你的问题,请参考以下文章