Android - getting from a Uri to an InputStream to a byte array?
Asked Answered
M

7

37

I'm trying to get from an Android Uri to a byte array.

I have the following code, but it keeps telling me that the byte array is 61 bytes long, even though the file is quite large - so I think it may be turning the Uri string into a byte array, rather than the file :(

  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");

Please can someone help me work out what to do?

The output is "fileUriString = content://media/external/video/media/53" and "len of data is 61 bytes".

Thanks!

Mccaskill answered 12/3, 2010 at 22:46 Comment(2)
what's cR? You ask how to go "from a Uri to an InputStream" but you already got an InputStream, without saying how you got it.Robespierre
@Robespierre the cR is an instance of ContentResolver classEquipotential
G
80

is.toString() will give you a String representation of the InputStream instance, not its content.

You need to read() bytes from the InputStream into your array. There's two read methods to do that, read() which reads a single byte at a time, and read(byte[] bytes) which reads bytes from the InputStream into the byte array you pass to it.


Update: to read the bytes given that an InputStream does not have a length as such, you need to read the bytes until there is nothing left. I suggest creating a method for yourself something like this is a nice simple starting point (this is how I would do it in Java at least).

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();
}
Groin answered 12/3, 2010 at 22:51 Comment(4)
Thank you. That doesn't solve the problem though, because I have to specify the length of the byte[] array before I supply it, and I can't get that from an InputStream. Any idea how I can work out the length of the data given the Uri?Mccaskill
You don't have to know the file size in advance. The proposed solution will work with any stream length.Distaff
why do we need to declare a buffer size? could w eput any length and if so, is there no way to put entire contents at once?Elegiac
@Mccaskill I'm not sure if it helps, but to read the number of bytes from input stream you can call .available() methodDiatomaceous
E
11

With Apache Commons, you can read all the bytes from a Stream thanks to IOUtils.toByteArray(InputStream) as next:

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

download jar: http://commons.apache.org/io/download_io.cgi

Edo answered 14/5, 2012 at 20:7 Comment(0)
B
7

Kotlin way:

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

In Kotlin, they added convenient extension functions for InputStream like buffered, use, and readBytes.

  • buffered decorates the input stream as BufferedInputStream
  • use handles closing the stream
  • readBytes does the main job of reading the stream and writing into a byte array

Error cases:

  • IOException can occur during the process (like in Java)
  • openInputStream can return null. If you call the method in Java you can easily oversee this. Think about how you want to handle this case.
Berl answered 17/1, 2019 at 17:8 Comment(0)
D
3
while ((len = inputStream.read(buffer)) != -1)

should be

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

This way read will not block if stream has no available bytes as explained in this answer.

Daze answered 26/1, 2012 at 10:48 Comment(1)
Blocking is the correct behaviour if you have only received half the file. Checking availability is a dreadful alternative to checking for end of file.Swing
O
1

With Google Guava, you can use ByteStreams.toByteArray(InputStream) to get all the bytes in the input stream:

InputStream is = ...;
byte[] bytes = ByteStream.toByteArray(is);
Octodecimo answered 20/5, 2014 at 1:18 Comment(0)
T
0

Sharing my idea :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;
}
Typhogenic answered 12/5, 2013 at 10:13 Comment(1)
InputStreamReader is use Big5 encoding format, because my content have chinese character, you can use UTF-8Typhogenic
P
0

if You have an Uri, instead of a regular file name, you should use Content Resolver. Android: Getting a file URI from a content URI?

I tried this, and it works. Uri uri; // it is something, I've got from a file chooser. Of course, I must be sure, that the uri points to a filename, and it is not an image, or audio, or something else...

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

I've omitted some try-catch-finally from the code, but the most important things are here. The first thing is, that if you have an uri, you cannot use the standard file reader.

Pharr answered 13/9, 2015 at 20:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.