Here
ArrayList<Integer> byteArray = new ArrayList<Integer>();
int tempByte;
do {
tempByte = stream.read();
byteArray.add(tempByte);
you are writing every byte straight into memory in an array of integers! Every integer consumes 4 bytes of memory while you just need one byte of it for every read byte. Effectively you should be using ArrayList<Byte>
or better byte[]
instead since every byte
costs only one byte of memory, but that would per saldo still allocate as much memory as the file large is.
And here
byte[] bytes = new byte[byteArray.size()];
you're allocating afterwards as much memory as the file large is. Per saldo you're with both ArrayList<Integer>
and byte[]
allocating 5 times as much memory as the file large is.
It's a waste.
You should write it to an OutputStream
immediately, e.g. FileOutputStream
.
InputStream input = null;
OutputStream output = null;
try {
input = license.openStream();
output = new FileOutputStream("/file.ext");
byte[] buffer = new byte[1024];
for (int length; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}
This costs effectively only 1KB of memory for the buffer instead of the whole file length of bytes (or 4 times of it when using integers).
Or if you really want to have it in a byte[]
then just skip the whole ArrayList<Integer>
step. It makes no sense. Use an ByteArrayOutputStream
as OutputStream
.
InputStream input = null;
ByteArrayOutputStream output = null;
try {
input = license.openStream();
output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
for (int length; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}
byte[] bytes = output.toByteArray();
This however still costs as much memory as the file large is, it's only now not 5 times of file size anymore as you initially did with ArrayList<Integer>
and a byte[]
afterwards.
Update: as per your comment you'd like to store this in the database. You can also do this without storing the whole file in Java's memory. Just write the obtained InputStream
immediately to the DB using PreparedStatement#setBinaryStream()
.
final String SQL = "INSERT INTO file (filename, contentType, content) VALUES (?, ?, ?)";
String filename = FilenameUtils.getName(license.getName());
InputStream input = license.openStream();
Connection connection = null;
PreparedStatement statement = null;
try {
connection = database.getConnection();
statement = connection.prepareStatement(SQL);
statement.setString(1, filename);
statement.setString(2, getServletContext().getMimeType(filename));
statement.setBinaryStream(3, input);
statement.executeUpdate();
} catch (SQLException e) {
throw new ServletException("Saving file in DB failed", e);
} finally {
if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
if (connection != null) try { connection .close(); } catch (SQLException logOrIgnore) {}
}