Resource leak: stream is never closed - android

Short way to reproduce the problem in my real project. Environment: Android SDK 1.16, Eclipse 4.2.0, Windows. Create default Android application and add the following code to MainActivity.java:
private void Save1(boolean externalStorage)
{
String s = "12345";
File file;
FileOutputStream fos = null;
if ( externalStorage )
{
try
{
file = new File(getExternalFilesDir(null), "log");
fos = new FileOutputStream(file); // Resource leak: 'fos' is never closed
}
catch(FileNotFoundException e)
{
return;
}
}
else
{
try
{
fos = openFileOutput("log", Context.MODE_PRIVATE);
}
catch(FileNotFoundException e)
{
return;
}
}
try
{
fos.write(s.getBytes());
fos.close();
}
catch(IOException e)
{
return;
}
}
private void Save2(boolean externalStorage)
{
String s = "12345";
File file;
FileOutputStream fos = null;
try
{
file = new File(getExternalFilesDir(null), "log");
fos = new FileOutputStream(file); // OK
}
catch(FileNotFoundException e)
{
return;
}
try
{
fos.write(s.getBytes());
fos.close();
}
catch(IOException e)
{
return;
}
}
Line fos = new FileOutputStream(file) in Save1 function, warning: Resource leak: 'fos' is never closed
The same line in Save2 function: no warnings.
Please don't send untested answers, the problem is not so simple as it looks. Adding fos.close() to different parts of the function doesn't help.

It also go away if i add an finally block to the try in the if block like this:
if (externalStorage) {
try {
fos = new FileOutputStream(new File(getExternalFilesDir(null),
"log"));
} catch (FileNotFoundException e) {
return;
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
try {
fos = openFileOutput("log", Context.MODE_PRIVATE);
} catch (FileNotFoundException e) {
return;
}
}
It is getting interesting...
So my guess would be, So if you are opening an Stream in a try block and catch block has an return statement then there should be a finally block that close the stream.
Something like that..
A tried the same code in a simple java project in eclipse and still got the warning. So it looks like is not related to lint or android. It looks like the eclipse compiler issue. Following is the code, I had to create a dummy openFileOutput() method since it is not available n java:
private void Save1(boolean externalStorage) {
String s = "12345";
FileOutputStream fos = null;
if (externalStorage) {
try {
fos = new FileOutputStream(new File("c://", "log"));
} catch (FileNotFoundException e) {
return;
}
} else {
try {
fos = openFileOutput("log", -1);
} catch (FileNotFoundException e) {
return;
}
}
try {
fos.write(s.getBytes());
fos.close();
} catch (IOException e) {
return;
}
}
/**
* #param string
* #param i
* #return
*/
private FileOutputStream openFileOutput(String string, int i)
throws FileNotFoundException {
return null;
}

This isn't an answer, but added here for clarity to the OP and other readers rather than a comment.
I've tested this in IDEA 11.2 API 15 using the current versions of the platform tool chain (Rev 14 Oct 2012) and there is no lint warning, compile error or runtime error. I forced the method to go through each path by creating exceptions and setting useExternalStorage both true and false.
My guess is this is a lint/compile error in your tool chain or possibly Eclipse (although unlikely, does Eclipse itself do any checking like this?).
[EDIT]
Just a thought, (and I would test but I've forgotten how to use Eclipse) but FileInputStream(file) might throw a SecurityException which would be thrown to somewhere up in your call stack. What happens if you catch it?
[EDIT]
This is the closest warning I get, and not at all relevant. I'm convinced the warning is not down to you.

In case of an Exception, fos wont be closed. Adding a finally to the try-catch would solve this issue.
try
{
fos = openFileOutput("log", Context.MODE_PRIVATE);
}
catch(FileNotFoundException e)
{
return;
}
//add this:
finally {
if (fos != null) {
fos.close();
}
}

Related

writeDataToFile(String) may fail to clean up java.io.Writer on checked exception in FindBugs

I'm using FileWrite class to Write into a file.and its working fine. But FindBugs is pointing me a Minor issue in my code snippet.
code snippet:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd");
Date now = new Date();
String fileName = formatter.format(now) + ".txt";
FileWriter writer = null;
try {
File root = new File(Environment.getExternalStorageDirectory(), "Test");
if (!root.exists()) {
root.mkdirs();
}
File gpxfile = new File(root, fileName);
writer = new FileWriter(gpxfile, true);
writer.append(text + "\n\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Findbug Report:
OBL_UNSATISFIED_OBLIGATION: Method may fail to clean up stream or resource
writeDataToFile(String) may fail to clean up java.io.Writer on checked exception
In which line i'm getting this Error?
writer = new FileWriter(gpxfile, true);
Could some one please brief me what is this exactly?
And how can we solve this?
You are getting this error because of writer.flush();. This could lead to IOException since it writes any buffered output to the underlying stream. If the exception occurs the writer won't be closed.
If its mandatory to flush in finally{..} then use dedicated try{..} catch{..} for each line as follows:
finally {
if (writer != null) {
try {
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Getting SQL file from physical phone in device monitor not working?

I have noticed in the android device monitor when I try to access the data folder so I can pull the sql file of my application that is running on my physical phone it does not work but when accessing the application through an emulator it does work. Obviously running the application on the emulator is much more time consuming and I need to present this sqlite data in a timed viva so I can't really be waiting for an emulator.
I was wondering why this is happening as I have allowed debugging and while it does not ask for any more checks on security the device monitor will not open the data folder, when clicked the arrowhead next to the folder disappears then reappears after a few seconds but I can still access every other folder with a drop-down arrow next to it.
If your device is not rooted, you cannot access your app's data file. Try to use following code snippet in any of your Activity to copy the file to sdcard.
public static void copyDataFile() {
File dataDir = getFilesDir().getParentFile();
File target = new File(dataDir, "/* relative path to your sql file */");
File out = new File(Environment.getExternalStorageDirectory(), "/* new file name */");
copyFile(target, out);
}
public static void copyFile(File in, File out) {
if (in.exists()) {
if (!out.exists()) {
try {
out.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileInputStream is = null;
FileOutputStream os = null;
try {
is = new FileInputStream(in);
os = new FileOutputStream(out);
byte[] buf = new byte[4096];
int l = 0;
while ((l = is.read(buf)) > 0) {
os.write(buf, 0, l);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

Read a file, if it doesn't exist then create

Honestly, I've searched a lot do this task so I ended up trying various methods but nothing worked until I ended up on this code. It works for me perfectly like it should, so I do not want to change my code.
The help I need is to put this code in a such a way that it begins to read a file, but if it the file doesn't exist then it will create a new file.
Code for saving data:
String data = sharedData.getText().toString();
try {
fos = openFileOutput(FILENAME, MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Code for loading data:
FileInputStream fis = null;
String collected = null;
try {
fis = openFileInput(FILENAME);
byte[] dataArray = new byte [fis.available()];
while (fis.read(dataArray) != -1){
collected = new String(dataArray);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So If I add the saving data code in to the "FileNotFoundException" catch of the loading data part then could I achieve what I want?
Add
File file = new File(FILENAME);
if(!file.exists())
{
file.createNewFile()
// write code for saving data to the file
}
above
fis = openFileInput(FILENAME);
This will check if there exists a File for the given FILENAME and if it doesn't it will create a new one.
If you're working on Android, why don't you use the API's solution for saving files?
Quoting:
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
You should really read the whole document, they explain pretty well the basic ways of creating or accessing files, you can also check the different ways of storing data.
But regarding your original question:
So If I add the saving data code in to the "FileNotFoundException"
catch of the loading data part then could I achieve what I want?
Yes, you could achieve it.
Try this one:
public static void readData() throws IOException
{
File file = new File(path, filename);
if (!file.isFile() && !file.createNewFile()){
throw new IOException("Error creating new file: " + file.getAbsolutePath());
}
BufferedReader r = new BufferedReader(new FileReader(file));
try {
// ...
// read data
// ...
}finally{
r.close();
}
}
Ref: Java read a file, if it doesn't exist create it

Resource leak warning on file stream

private void SaveLog(boolean externalStorage)
{
String s = tv_log.getText().toString();
File file;
FileOutputStream fos;
if ( externalStorage )
{
try
{
file = new File(getExternalFilesDir(null), FILE_LOG);
fos = new FileOutputStream(file); // Warning: Resource leak: 'fos' is never closed
}
catch(FileNotFoundException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
}
else
{
try
{
fos = openFileOutput(FILE_LOG, Context.MODE_PRIVATE);
}
catch(FileNotFoundException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
}
try
{
fos.write(s.getBytes());
fos.close();
}
catch(IOException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
}
Why the warning is shown in the line fos = new FileOutputStream(file)? Interesting, that if I remove if ( externalStorage ) and leave only the first branch, the warning is not shown:
private void SaveLog(boolean externalStorage)
{
String s = tv_log.getText().toString();
File file;
FileOutputStream fos;
try
{
file = new File(getExternalFilesDir(null), FILE_LOG);
fos = new FileOutputStream(file); // OK!
}
catch(FileNotFoundException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
try
{
fos.write(s.getBytes());
fos.close();
}
catch(IOException e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
}
I believe that in your specific case there isn't any possibility of resource leak as the line fos = new FileOutputStream(file);is the last line before the end of the try group, and if you have an exception in here the resource fos wouldn´t be created.
However, if you would have a statement after that line, that statement could genetare a exception, the execution would move to the catch group that is terminated with a return without releasing resources allocated in the trygroup.
The easiest way to avoid the warning is to add the following in the catch:
catch(FileNotFoundException e)
{
try { if(fos != null) fos.close();} catch (Exception e2) {} //Add this line
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
This would ensure that resource will be released if there is an exception raised.
In every catch block, close the stream using fos.close().
Otherwise, the program might hit the try block, generate an exception and go to the catch block without ever closing the stream. This might be causing the error.

Android: How to store data on internal memory?

It's perfectly described here how to do it, the only problem: He doesnt know the function openFileOutput();
private void saveSettingsFile() {
String FILENAME = "settings";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); //openFileOutput underlined red
try {
fos.write(string.getBytes());
fos.close();
} catch (IOException e) {
Log.e("Controller", e.getMessage() + e.getLocalizedMessage() + e.getCause());
}
}
Those are the relevant packages I imported:
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
Have a look at this example of using a FileOutputStrem from the Examples on dev.android.com. It should give you an idea of how to use it correctly.
Class within which this method is declared, is defined as "Static". thats why it is throwing error. Remove static from the class definition and bingo...
Just add a "try catch" block and put them in between this.
Like this:
private void saveSettingsFile(String FILENAME, String data) {
FileOutputStream fos;
try {
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} // openFileOutput underlined red
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When there is red line under the line.. First check that the line is under the full sentense or only right side of the sentense .(i.e after equal sign).
If it covers the whole line, then it has to fix some bugs..
Or if it under only the right side of the sentense ...Then it must wants some exception handling things.
If you don't know what type of exception it may generate...
Dont fear , just write all the code in a try block( try{ } ) and then add a catch and pass a Exception object inside catch .. Now its fine..
Like this :
try
{
...........your code
......
}
catch(Exception e)
{
e.printstacktrace();
}
Now all are fine.
Thank you
openFileOutput is a method of Context object. And don't forget to add finally clause to close the stream. Bellow is an example (a bit clumsy because of Java 6 because of Android).
String data = "Hello";
FileOutputStream fos = null;
try {
fos = mContext.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(data.getBytes(Charset.defaultCharset()));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
mContext variable should be defined somewhere above and initialized like mContext = getApplicationContext() if you are inside of an activity

Categories

Resources