Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the size of the data received via EXTRA_STREAM in an application handling the action send intent?

When another application is sending a file to my app, I get a Uri via the intent.getExtras().get(EXTRA_STREAM) property. I can then get the bytes of the file using an inputstream : new BufferedInputStream(activity.getContentResolver().openInputStream(uri));

Everything's OK and working so far. Now I'd like to show some kind of progress to my user, but I'm not sure of how to get the total number of bytes of the file without reading the stream completely beforehand (which would defeat the whole purpose of the progress bar) ...

I tried ParcelFileDescriptor fileDesc = activity.getContentResolver().openFileDescriptor(uri, "r"); but this only works with uris of type file://....

For example If I receive a file from Skydrive I get a content://.. Uri, as in : content://com.microsoft.skydrive.content.external/external_property/10C32CC94ECB90C4!155/Sunset.480p.mp4

On such Uri I get (unsurprisingly) a "FileNotFoundException : Not a whole file" exception.

Any sure fire way to get the total size of the stream of data I will get ?

like image 821
Sébastien Nussbaumer Avatar asked Sep 09 '13 15:09

Sébastien Nussbaumer


2 Answers

Even though InputStream.available() is (almost) never a recommended way of getting file size, it might be a viable solution in your case.

The content is already available locally. A server is not involved. So, the following should return the exact file size:

try {

    InputStream inputStream = getContentResolver().openInputStream(uri);

    Log.i("TEST", "File Size: " + inputStream.available());

} catch (FileNotFoundException fnfe) {

    fnfe.printStackTrace();

} catch (IOException ioe) {

    ioe.printStackTrace();

}

I tested this with SkyDrive and Dropbox. The file sizes returned were correct.

like image 156
Vikram Avatar answered Oct 06 '22 05:10

Vikram


There is no general solution for getting the size of a stream, other than reading the entire stream. This is easily proven: One could create a web server that, for some URL, generates a random stream of text that is terminated at a random time. (In fact, I'm sure such URLs exist, whether by design or not :-) In such a case, the size of the stream isn't known until the last byte has been generated, never mind received.

So, the stream size, if it is sent by the server at all, has to be sent in an application-specific manner.

I've never worked with SkyDrive, but a google search for its API turned up this link, which has the following example for Android Java apps:

public void readFile() {
    String fileId =  "file.a6b2a7e8f2515e5e.A6B2A7E8F2515E5E!141";
       client.getAsync(fileId, new LiveOperationListener() {
        public void onError(LiveOperationException exception, LiveOperation operation) {
               resultTextView.setText("Error reading file: " + exception.getMessage());
           }
           public void onComplete(LiveOperation operation) {
            JSONObject result = operation.getResult();
            String text = "File info:" +
                "\nID = " + result.optString("id") +
                "\nName = " + result.optString("name");
               resultTextView.setText(text);
           }
       });
}

Based on other examples on that page, I would guess that something like result.optString("size") (or maybe result.optInt("size") ?) would give you the size of the file.

like image 27
Dan Breslau Avatar answered Oct 06 '22 03:10

Dan Breslau