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!

AP257
  • 89,519
  • 86
  • 202
  • 261
  • 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. – Vince Apr 17 '15 at 17:05
  • @Vince the `cR` is an instance of ContentResolver class – mbelsky Oct 02 '15 at 11:24

7 Answers7

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();
}
brabster
  • 42,504
  • 27
  • 146
  • 186
  • 1
    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? – AP257 Mar 13 '10 at 11:10
  • You don't have to know the file size in advance. The proposed solution will work with any stream length. – Nacho Coloma Apr 10 '13 at 14:11
  • 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? – Tanner Summers Aug 09 '16 at 00:46
  • @AP257 I'm not sure if it helps, but to read the number of bytes from input stream you can call `.available()` method – Kirill Karmazin Oct 15 '19 at 13:36
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

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
6

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.
Peter F
  • 3,633
  • 3
  • 33
  • 45
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.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
Filippo Mazza
  • 4,339
  • 4
  • 22
  • 25
  • 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. – David Sainty Jun 18 '15 at 01:18
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);
Jamal
  • 763
  • 7
  • 22
  • 32
Dat Nguyen
  • 1,626
  • 22
  • 25
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;
}
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.

Community
  • 1
  • 1