OutofMemory error while writing a large file Android - java

I'm trying to encrypt a large file which is 500MB but my code throws an out of memory error, for small files below 50MB the code works fine. Im using a third party library called JNCryptor for encryption, please have a look at my code and correct me if any mistake. Thanks in advance.
public void encrypt() {
String file = Environment.getExternalStorageDirectory() + "/sai/ravi_enc.exe";
byte[] filedata = null;
try {
filedata = IOUtils.toByteArray(new FileInputStream(file));
} catch (IOException e) {
e.printStackTrace();
}
JNCryptor cryptor = new AES256JNCryptor();
String password = "123456789";
try {
byte[] ciphertext = cryptor.decryptData(filedata, password.toCharArray());
String Outfile = Environment.getExternalStorageDirectory() + "/sai/ravi_dec.exe";
writeFile(ciphertext, Outfile);
System.out.println("Done");
} catch (CryptorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeFile(byte[] data, String fileName) throws IOException {
FileOutputStream out = new FileOutputStream(fileName);
out.write(data);
out.close();
}

This is up to JNCryptor to well manage memory, especially if it uses temp buffer. It is better to work on streams instead of buffers. Just for testing, if you write directly the fileData to your outFile, do you get OutOfMemoryError?
writeFile(filedata, Outfile);

Related

How to decrypt .dat file with (possibly) java code?

I have a .dat file downloaded from a game, which appears to have some Java code or values in it, along with other illegible text. Here's some of the content:
My question is, is there any way I can decode this file? Or, how can I work out which encryption algorithm it uses so I can search more accurately on how to decrypt it?
The solution from #user207421 worked perfectly, i ended up using this code to get the file info:
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream("./file.dat");
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
try {
System.out.println(inputStream.readObject());
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}

Uncompressing base64 gzip on S3 and saving to local file system

I am a Java bonehead/newbie so please be gentle. I have two functions which I realize are somewhat incompatible:
saveS3toFilesystem - takes a InputStream from AWS S3 and saves it to the local filesystem as a file
decompress - takes a string and decodes the base64 encoding and the decompresses the gzip compression.
I really want these two to work in concert to achieve the result of the file saved to the filesystem being the uncompressed file but I realize that my "decompress" function should probably be changed to receive a stream rather than a string but sadly I'm just a "cutter and paster" in the world of Java these days.
Here are my two functions as they are now:
private void saveS3toFilesystem(String filename, String bucketName, String localFilename) {
S3Object obj = s3.getObject(bucketName, filename);
InputStream in = obj.getObjectContent();
try {
Files.createDirectories(Paths.get(localFilename.replace(this.FILE_EXTENSION, "")));
Files.copy(in, Paths.get(localFilename));
this.logger.log("Input file has been placed in local filesystem for ITMS to pick up: " + localFilename + "\n");
} catch (IOException err) {
this.logger.log("There was a problem saving the file to " + localFilename);
err.printStackTrace();
} finally {
try {
in.close();
} catch (IOException err) {
err.printStackTrace();
}
}
return;
}
and then ...
private String decompress(String compressedZip) {
byte[] decodedBytes = Base64.getDecoder().decode(compressedZip);
String result = null;
GZIPInputStream zip = null;
try {
zip = new GZIPInputStream(new ByteArrayInputStream(decodedBytes));
result = IOUtils.toString(zip);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(zip);
}
return result;
}
Can anyone please help me to achieve the dream? Happy to do it with streams, strings, or any method that will work. Sadly I can't afford atm to up my Java skills enough to grok the solution myself.
Many thanks in advance.
Based on the following APIs :
Base64.Decoder and GZIPInputStream (look at the wrap method on the former and the constructors on the latter), the decompress method can be overloaded as follows:
private String decompress(InputStream compressedStream) {
InputStream decodingStream = Base64.getDecoder().wrap(compressedStream);
String result = null;
GZIPInputStream zip = null;
try {
zip = new GZIPInputStream(decodingStream);
result = IOUtils.toString(zip);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(zip);
}
return result;
}
And finally, the changes to saveS3toFilesystem are as follows :
private void saveS3toFilesystem(String filename, String bucketName, String localFilename) {
S3Object obj = s3.getObject(bucketName, filename);
InputStream in = obj.getObjectContent();
// decoding the inputstream via decode into a string, which is then
// used in order to create an inputstream of decoded data
InputStream decodedStream =
new ByteArrayInputStream(decompress(in).getBytes(StandardCharsets.UTF_8));
try {
Files.createDirectories(Paths.get(localFilename.replace(this.FILE_EXTENSION, "")));
Files.copy(decodedStream, Paths.get(localFilename));
this.logger.log("Input file has been placed in local filesystem for ITMS to pick up: " + localFilename + "\n");
} catch (IOException err) {
this.logger.log("There was a problem saving the file to " + localFilename);
err.printStackTrace();
} finally {
try {
in.close();
} catch (IOException err) {
err.printStackTrace();
}
}
return;
}

My deflater class works incorecctly

My compression class works incorrectly. When i am trying to compress simple file that contains sentence "something", compressed and uncompressed returns something other. Here is my deflating code:
public static void inflate(String arg) throws Exception {
try {
FileInputStream fin = new FileInputStream(arg);
InflaterInputStream in = new InflaterInputStream(fin);
FileOutputStream fout = new FileOutputStream("def.txt");
int i;
while ((i = in.read()) != -1) {
fout.write((byte) i);
fout.flush();
}
fin.close();
fout.close();
in.close();
} catch (Exception e) {
System.out.println(e);
}
new File(arg).delete();
new File("def.txt").renameTo(new File(arg));
}
public static void deflate(String arg) throws Exception {
try {
FileInputStream fin = new FileInputStream(arg);
FileOutputStream fout = new FileOutputStream("def.txt");
DeflaterOutputStream out = new DeflaterOutputStream(fout);
int i;
while ((i = fin.read()) != -1) {
out.write((byte) i);
out.flush();
}
fin.close();
out.close();
} catch (Exception e) {
System.out.println(e);
}
new File(arg).delete();
new File("def.txt").renameTo(new File(arg));
}
I call it using
public static void main(String[] args) {
try {
Main.deflate(args[0]);
Main.inflate(args[0]);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So how to fix my code? I think that problem is not in deflating code.
Your code does seem to work as expected.
Running it on a text file containing the word 'something' returns an identical file.
To confirm that the output is the same, try editing the following lines:
Test.inflate("def.txt");
which is in your main function and
FileOutputStream fout = new FileOutputStream("output.txt");
from your inflate function.
Then comment out the following lines in both your deflate() and inflate() functions
//new File(arg).delete();
//new File("def.txt").renameTo(new File(arg));
The program will now take an input file, I used input.txt with the word 'something' as per your example, and create a deflated file def.txt and an output.txt file that is created by inflating def.txt.
The output file should match the input file exactly, while the deflated file should be different. If not, there must be some further information about the program that is missing.

Convert encoded base64 image to File object in Android

I am trying to use the AndroidImageSlider library and populate it with images that I have downloaded as a base64 string.
The library only accepts URLs, R.drawable values, and the File object as parameters.
I am trying to convert the image string to a File object in order to be passed to the library function. I have been able to decode from base_64 and convert to a byte[] so far.
String imageData;
byte[] imgBytesData = android.util.Base64.decode(imageData, android.util.Base64.DEFAULT);
You'll need to save the File object to disk for that to work. This method will save the imageData string to disk and return the associated File object.
public static File saveImage(final Context context, final String imageData) {
final byte[] imgBytesData = android.util.Base64.decode(imageData,
android.util.Base64.DEFAULT);
final File file = File.createTempFile("image", null, context.getCacheDir());
final FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
fileOutputStream);
try {
bufferedOutputStream.write(imgBytesData);
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
It creates a temporary file in your applications 'cache' directory. However, you are still responsible for deleting the file once you no longer need it.

Using JarEntry to write sound files is not working as intended

public static void writeFile(String theFileName, String theFilePath)
{
try {
File currentFile = new File("plugins/mcMMO/Resources/"+theFilePath+theFileName);
//System.out.println(theFileName);
#SuppressWarnings("static-access")
JarFile jar = new JarFile(plugin.mcmmo);
JarEntry entry = jar.getJarEntry("resources/"+theFileName);
InputStream is = jar.getInputStream(entry);
byte[] buf = new byte[(int)entry.getSize()];
is.read(buf, 0, buf.length);
FileOutputStream os = new FileOutputStream(currentFile);
os.write(buf);
os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Alright so in my program I have various resources kept within the Jar of the program, when the program runs it has specific files passed to this function that are written to the HDD of the users computer. Everything gets written, but only the images come out 100% correct. The sound files are not so lucky.
Basically, I CANNOT get the sounds to write correctly, their file sizes are correct but they only contain a split second of audio instead of their full length audio. Am I missing something here? I seem to have done everything right, but if that was true I wouldn't be posting here.
I tried my best at googling this problem but it has failed me.
Any guess as to why this doesn't work would be AMAZING!! :)
As JarEntry extends ZipEntry, I would recommend not to rely on the ZipEntry.getSize() method as it return -1. See the doc.
Moreover, it's in general much more common to take advantage of buffering when reading a stream. In your example, you put everything inside your byte array, so I guess for big files you could end up in an OutOfMemoryError.
Here would be the code I would test:
public static void writeFile(String theFileName, String theFilePath)
{
try {
File currentFile = new File("plugins/mcMMO/Resources/"+theFilePath+theFileName);
#SuppressWarnings("static-access")
JarFile jar = new JarFile(plugin.mcmmo);
JarEntry entry = jar.getJarEntry("resources/"+theFileName);
InputStream is = jar.getInputStream(entry);
byte[] buf = new byte[2048];
int nbRead;
OutputStream os = new BufferedOutputStream(new FileOutputStream(currentFile));
while((nbRead = is.read(buf)) != -1) {
os.write(buf, 0, nbRead);
}
os.flush();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

Categories