0

In my android App I download some photographs from the internet.How can I verify that an image from the web is correctly downloaded? I've thought of checking the file's size I've just written on sd is greater that zero, but I don't know if this is sufficient. this is my code

    String filename =title.replace(" ","")+j+".nomedia";
    File destination = new File(MyApplication.getPhotoStorage() ,filename);


    URL url = new URL (url_image);

    InputStream is = url.openStream();
    OutputStream os = new FileOutputStream(destination);


    byte[] b = new byte[2048];
    int length;

    while ((length = is.read(b)) != -1) {
    os.write(b, 0, length);
    }

    is.close();
    os.close();
    localPhotosUrl.add(destination.getAbsolutePath());
Libathos
  • 3,340
  • 5
  • 36
  • 61

3 Answers3

2

The only possibility I can think of is comparing the files checksums. Thus the server would have to provide the checksums for the files it provides. Then youl would download the file and the checksum, generate the checksum for the downloaded file locally and then compare the downloaded checksum with the generated. The checksums can be generated for example with MD5 but there are other hashing algorithms, too.

Here is shown how you can generate the MD5 checksum for files in Java without much overhead: Getting a File's MD5 Checksum in Java

For your code it would be applied like this:

String filename =title.replace(" ","")+j+".nomedia";
File destination = new File(MyApplication.getPhotoStorage() ,filename);


URL url = new URL (url_image);

OutputStream os = new FileOutputStream(destination);

MessageDigest md = MessageDigest.getInstance("MD5");
try (InputStream is = url.openStream()) {
    DigestInputStream dis = new DigestInputStream(is, md);
    byte[] b = new byte[2048];
    int length;

    while ((length = dis.read(b)) != -1) {
        os.write(b, 0, length);
    }
}

byte[] digest = md.digest();

os.close();
localPhotosUrl.add(destination.getAbsolutePath());
Community
  • 1
  • 1
stevecross
  • 5,588
  • 7
  • 47
  • 85
  • Ok I got it really nice way, how can I generate the checksums on the server side also? – Libathos Apr 11 '14 at 08:22
  • Basically the same way. You have to generate the checksums everytime a file is added and you need a way to read the checksum from the server. Often the checksum is stored next to the original file with the same name but with the .md5 file extension. – stevecross Apr 11 '14 at 08:25
  • Inside the try block you have to read from `dis` not from `is`. I changed it now. – stevecross Apr 11 '14 at 08:28
1

I guess the easiest way here would be to try to decode it with Bitmap.DecodeFile. If your bitmap can properly be loaded, then it has been downloaded successfully.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int width = opts.outWidth;
int height = opts.outHeight;

We use options.inJustDecodeBounds so that as to keep memory usage low. We don't want a copy of the bitmap but just to check the decoder knows what to do with the file.

If width and height are greater than zero, your bitmap is not corrupted.

Obviously this only works because you are downloading photos and not some random files. If these can ben any kind of files then the md5 answer is a good one.

Yahel
  • 8,522
  • 2
  • 24
  • 32
  • wouldn't this take a lot of time though? – Libathos Apr 11 '14 at 08:48
  • No, it is really quick. It's a matter of milliseconds, compared to the time it takes to download a photo, this really is not an overhead. – Yahel Apr 11 '14 at 08:49
  • oh ok, thanks for pointing it out, I've upvoted you since I've an accepted answer, you really helped me though – Libathos Apr 11 '14 at 08:50
  • Beside the injustdecodebound makes it fairly light on the memory side. It's only 6 lines of code, simply try it quickly in your code and see how it behaves. It's a lot easier in my mind than having the server compute some md5 and store it some way :D – Yahel Apr 11 '14 at 08:51
0

Unless the server also provides some sort of hash value alongside the files (SHA1, MD5, etc.), you can't really. You could try parsing the image file (create a Bitmap, etc.) object, but that could be too memory intensive if you are downloading a lot of files. Just keep it best effort :)

Nikolay Elenkov
  • 52,576
  • 10
  • 84
  • 84