OutOfMemory Error in ByteArrayOutputStream while writing 'n' number of files - android

i am writing the PDF's to sdcard and using the below code :
byte[] data = new byte[20000];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
InputStream fileInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
while ((nRead = fileInputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] bytesToWrite = buffer.toByteArray();
fileInputStream.read(bytesToWrite);
fileInputStream.close();
FileOutputStream fileOutputStream = null;
String outputFileName = outputDirName + "/" + fileName;
fileOutputStream = new FileOutputStream(outputFileName);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
bos.write(bytesToWrite);
bos.flush();
bos.close();
It works fine if i am trying to write 20 PDFs in one shot, but if its more than that it gives me OutOfMemory error.
what might be the issue ?

You are storing the entire file into RAM with your ByteArrayOutputStream, then copying it from RAM onto disk. This is likely what's causing your OutOfMemoryError.
It would be much more efficient to read a chunk into RAM, and then flush to disk immediately repeatedly. I've rewritten your code to do this.
byte[] data = new byte[20000];
FileOutputStream fileOutputStream = null;
String outputFileName = outputDirName + "/" + fileName;
fileOutputStream = new FileOutputStream(outputFileName);
int nRead;
InputStream fileInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
while ((nRead = fileInputStream.read(data, 0, data.length)) != -1) {
fileOutputStream.write(data,0,nRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();

Related

Unable to create byte[] array of file and vice versa - android

I am unable to create byte[] array of file and and re-create byte[] to file. File creates from byte[] array with exact size what was before, but unable to open it. It say's format is not supported. Like-wise I have to do for more file's like video, audio, docs etc. I have tried answer's available in stack-overflow but no success.
Here is my code:-
To convert image into byte[] array
public static byte[] getBytesFromImage() {
FileInputStream in;
try {
File photo = new File(Environment.getExternalStorageDirectory(), "nature.jpg");
FileInputStream fis = new FileInputStream(photo);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
for (int readNum; (readNum = fis.read(b)) != -1;) {
bos.write(b, 0, readNum);
}
bMapArray = bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return bMapArray;
}
To convert byte[] array into image file.
public static String getImageFromBytesTemp() {
File file = new File(Environment.getExternalStorageDirectory(), "nature2.jpg");
if (file.exists()) {
file.delete();
}
try {
FileOutputStream fos=new FileOutputStream(file.getAbsolutePath());
fos.write(bMapArray);
fos.close();
}
catch (IOException e) {
e.printStackTrace();
}
return file.getAbsolutePath();
}
Your code is ok,
maybe you simply need to flush your ByteArrayOutputStream
for (int readNum; (readNum = fis.read(b)) != -1;) {
bos.write(b, 0, readNum);
}
bMapArray = bos.toByteArray();
bos.flush();
bos.close();

Reading a file from external SD card in android Marshmallow 6.0.1 giving fileNotFoundException open failed: ENOENT

I am trying to read a file from external SD card in android Marshmallow 6.0.1 and want to convert in Base64, but it is giving ENOENT(fileNotFoundException). But my same code is working for 6.0 and below. My code is as follows:
private String convertFileToByteArray(File file) { //file path as: /storage/emulated/0/abc.doc
byte[] byteArray = null;
try {
File f=new File(file.toString());
Log.e("File EXISTs: >>",""+f.exists());
//getting error in this line,giving fileNotFoundException
FileInputStream inputStream = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024 * 11];
int bytesRead = 0;
while ((bytesRead = inputStream.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
byteArray = bos.toByteArray();
Log.e("Byte array", ">" + byteArray);
} catch (IOException e) {
e.printStackTrace();
}
return Base64.encodeToString(byteArray, Base64.NO_WRAP);
}
Can any one suggest me what's wrong i am doing here. PS: I am giving runtime permissions also(read and write).

Use OkHttp to download lots of images to sd card

So a part of my app downloads a large number (~1600) of images to SdCard using an IntentService. I previously used Glide, but now want to switch to OkHttp, since it seems to be faster and less battery consuming. This is my current code:
for (int i = 1; i < 1600; i++) {
try {
Request request = new Request.Builder()
.url(imageUrls[i])
.build();
Response response = client.newCall(request).execute();
File testDirectory = new File(Environment.getExternalStorageDirectory()
+ "/downloadTest");
if (!testDirectory.exists())
testDirectory.mkdirs();
OutputStream outputStream = new FileOutputStream(new File(testDirectory,
"testImage" + i + ".png"));
InputStream inputStream = response.body().byteStream();
byte[] buffer = new byte[1024];
int read;
while ((read = inputStream.read(buffer, 0, buffer.length)) >= 0)
outputStream.write(buffer, 0, read);
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Is there any way I could optimize this code to make downloading faster?
You can use Okio instead of InputStream/OutputStream to save some copies. Something like this:
BufferedSink sink = Okio.buffer(Okio.sink(new File(testDirectory, "testImage" + i + ".png")));
sink.writeAll(response.body().source());
sink.close();
response.body().close();
See this post for an explanation of why this is faster.
the easiest way is:
InputStream inputStream = response.body().byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
and save the bitmap as jpg:
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}

Reading a resource sound file into a Byte array

I have cheerapp.wav or cheerapp.mp3 or some other format.
InputStream in = context.getResources().openRawResource(R.raw.cheerapp);
BufferedInputStream bis = new BufferedInputStream(in, 8000);
// Create a DataInputStream to read the audio data from the saved file
DataInputStream dis = new DataInputStream(bis);
byte[] music = null;
music = new byte[??];
int i = 0; // Read the file into the "music" array
while (dis.available() > 0) {
// dis.read(music[i]); // This assignment does not reverse the order
music[i]=dis.readByte();
i++;
}
dis.close();
For the music byte array which takes the data from the DataInputStream. I don't know what the length of that to allocate.
This is raw file from resource not a file therefore I wouldn't know the size of that thing.
You do have byte array length as you can see:
InputStream inStream = context.getResources().openRawResource(R.raw.cheerapp);
byte[] music = new byte[inStream.available()];
And then you can read whole Stream into byte array easily.
Of course I would recommend that you do check when it comes to the size and use ByteArrayOutputStream with smaller byte[] buffer if needed:
public static byte[] convertStreamToByteArray(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[10240];
int i = Integer.MAX_VALUE;
while ((i = is.read(buff, 0, buff.length)) > 0) {
baos.write(buff, 0, i);
}
return baos.toByteArray(); // be sure to close InputStream in calling function
}
If you'll be doing lots of IO operations I recommend that you make use of org.apache.commons.io.IOUtils. That way you won't need to worry too much about quality of your IO implementation and once you import JAR into your project you would just do:
byte[] payload = IOUtils.toByteArray(context.getResources().openRawResource(R.raw.cheerapp));
Hope it will help.
Create an sdcard path:
String outputFile =
Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";
Convert as a file and have to call the byte array method:
byte[] soundBytes;
try {
InputStream inputStream =
getContentResolver().openInputStream(Uri.fromFile(new File(outputFile)));
soundBytes = new byte[inputStream.available()];
soundBytes = toByteArray(inputStream);
Toast.makeText(this, "Recordin Finished"+ " " + soundBytes, Toast.LENGTH_LONG).show();
} catch(Exception e) {
e.printStackTrace();
}
method:
public byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read = 0;
byte[] buffer = new byte[1024];
while (read != -1) {
read = in.read(buffer);
if (read != -1)
out.write(buffer,0,read);
}
out.close();
return out.toByteArray();
}
In Kotlin use
InputStream.readBytes()

Android : How to determine the file extension of a file

I am trying to share files between two Android phones using Socket programming. The problem is right now I have to hard code the file extension on the receiving end. Is there a way that I can automatically determine the extension of the file being received?
Here's my code.
Client Side
socket = new Socket(IP,4445);
File myFile = new File ("/mnt/sdcard/Pictures/A.jpg");
FileInputStream fis = null;
fis = new FileInputStream(myFile);
OutputStream os = null;
os = socket.getOutputStream();
int filesize = (int) myFile.length();
byte [] buffer = new byte [filesize];
int bytesRead =0;
while ((bytesRead = fis.read(buffer)) > 0) {
os.write(buffer, 0, bytesRead);
System.out.println("SO sendFile" + bytesRead);
}
os.flush();
os.close();
fis.close();
socket.close();
}
And the Server side
FileOutputStream fos = null;
File root = Environment.getExternalStorageDirectory();
fos = new FileOutputStream(new File(root,"B.jpg")); //Here I have to hardcode B.jpg with jpg extension.
BufferedOutputStream bos = new BufferedOutputStream(fos);
ServerS = new ServerSocket(4445);
clientSocket = ServerS.accept();
InputStream is = null;
is = clientSocket.getInputStream();
int bytesRead = 0;
int current = 0;
byte [] mybytearray = new byte [329];
do {
bos.write(mybytearray,0,bytesRead);
bytesRead = is.read(mybytearray, 0, mybytearray.length);
} while(bytesRead > -1);
bos.flush();
bos.close();
clientSocket.close();
}
You can find the file extension pretty easily by doing this:
String extension = filename.substring(filename.lastIndexOf('.'));

Categories

Resources