Getting Out Of Memory Error when saving big files

Viewed 509

I'm trying to save file taken by another app into internal directory at background thread with this method :

 public static File saveUri(Uri uri,File file, WeakReference<Context> contextWeakReference) throws IOException {

        ContentResolver resolver=contextWeakReference.get().getContentResolver();

        InputStream inputStream=resolver.openInputStream(uri);
        ByteArrayOutputStream stream=new ByteArrayOutputStream();

        FileOutputStream fileOutputStream=new FileOutputStream(file);

        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            stream.write(buffer, 0, bytesRead);
        }
        

        fileOutputStream.write(stream.toByteArray());
        fileOutputStream.close();
        inputStream.close();
        return file ;

    }

and it works until I save file like 100 MB size. Above that it gives :

java.lang.OutOfMemoryError: Failed to allocate a 134217744 byte allocation with 25165824 free bytes and 124MB until OOM, max allowed footprint 95471864, growth limit 201326592

at this line :

stream.write(buffer, 0, bytesRead);

This is what I use for backround process :

public static final ExecutorService databaseWriteExecutor =
        Executors.newSingleThreadExecutor();

What should I do for saving big size file without causing Out Of Memory Error.

2 Answers

Not tested but you probably want a append the bytes to the FileOutputStream and write the buffer in the loop :

public static File saveUri(Uri uri, File file, ContentResolver resolver) {
    try (final OutputStream os = new FileOutputStream(file, true)) {
        final InputStream inputStream = resolver.openInputStream(uri);
        if (inputStream != null) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            inputStream.close();
        }
    } catch (IOException e) {
        Log.e(TAG, "Error writing file");
    }
    return file;
}

There are many ways to do this...

When you are reading from inputStream, you are not writing to the FileOutputStream you are saving all the content in memory on the stream variable.

Please, link both the streams, so the content of the file you are copying don't stay in memory

Related