0

I'm trying to download file at my android device. This is my code:

InputStream in = null;
ByteArrayOutputStream out = null;
FileOutputStream fos = null;

try {
    URL link = new URL(fileURL);
    in = new BufferedInputStream(link.openStream());
    out = new ByteArrayOutputStream();
    byte[] buf = new byte[8192];
    int n, bytesBuffered = 0;
    while (-1 != (n = in.read(buf))) {
        bytesBuffered += n;
        out.write(buf, 0, n);
        if (bytesBuffered >1048576) {
            bytesBuffered = 0;
            out.flush();
        }
    }
    byte[] response = out.toByteArray();
    fos = new FileOutputStream(filePath);
    fos.write(response);
    return true;

} catch (Throwable e) {
    e.printStackTrace();
    return false;
} finally {
//closing streams
}

It fails at out.write(buf, 0, n); with out of memory error. What is wrong? I've read I'm able to set bigger heap size at manifest, but I don't find it a good solution. What is wrong?

Tony
  • 3,605
  • 14
  • 52
  • 84
  • What is the size of the file you are reading? – amit Mar 23 '15 at 08:48
  • maybe you need to add `android:largeHeap="true"` in manifest! – Apurva Mar 23 '15 at 08:49
  • Also, what are you trying to achieve here? Just read a file - you really need to make sure the heap size is larger than the file in order to do so, however - often you don't really need to store the entire file to get an answer to some question about it. – amit Mar 23 '15 at 08:50
  • You don't need ByteArrayOutputStream, just read InputStream and write to FileOutputStream. – Lei Guo Mar 23 '15 at 08:53

3 Answers3

1

You are doing it wrong!

Open your FileOutputStream and just read from the input and copy it to the output stream:

private static final int BUFSIZE = 8096;

//

final byte[] buf = new byte[BUFSIZE];

int nrBytes;

while ((nrBytes = in.read(buf)) != -1)
    out.write(buf, 0, nrBytes);

(note: closing descriptors not handled here, left as an exercise; but sicne this is Android and you therefore don't have try-with-resource or even JSR 203, I suggest you use Guava and its Closer)

fge
  • 119,121
  • 33
  • 254
  • 329
1

if your goal is to write the content on a file, there is no need to read the content in memory before writing it.

fos = new FileOutputStream(filePath);
while (-1 != (n = in.read(buf))) {
    bytesBuffered += n;
    fos.write(buf, 0, n);
}
fos.flush();

and I would also add a finally clause to the try block to close fos. The finally block is call either if you return successfully or if an error occurs. This way you will not leak the FileOutputStream

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
0

You need a do instead of a while loop :

do {    
    n = in.read(buf); 
    bytesBuffered += n;
    out.write(buf, 0, n);
    if (bytesBuffered >1048576) {
        bytesBuffered = 0;
        out.flush();
    }
} while (n != -1)

and also add a finally block as pointed out by tony

Jai Mani
  • 11
  • 1
  • 2