How to properly close file-to-string input stream? (IOUtils FileUtils) - java

I have two file-to-string processes in my app (one actually deals with an asset file).
If I repeat either of these processes a few times on the same file, I get OutOfMemoryErrors.
I suspect it might be because I'm not closing the streams properly and therefore maybe causing multiple streams to be created, and this is perhaps causing my app to run out of memory.
Here is the code of the two processes:
My asset-file-to-string process.
As you can see, I have have something in place to close the stream but I don't know if it's formatted properly.
try
{
myVeryLargeString = IOUtils.toString(getAssets().open(myAssetsFilePath), "UTF-8");
IOUtils.closeQuietly(getAssets().open(myAssetsFilePath));
}
catch (IOException e)
{
e.printStackTrace();
}
catch(OutOfMemoryError e)
{
Log.e(TAG, "Ran out of memory 01");
}
My file-to-string process.
I have no idea how to close this stream (if there is even a stream to close at all).
myFile01 = new File(myFilePath);
try
{
myVeryLargeString = FileUtils.readFileToString(myFile01, "UTF-8");
}
catch (IOException e)
{
e.printStackTrace();
}
catch(OutOfMemoryError e)
{
Log.e(TAG, "Ran out of memory 02");
}

It's difficult to say what may cause OOME but closing should be like this
InputStream is = getAssets().open(myAssetsFilePath);
try {
myVeryLargeString = IOUtils.toString(is, "UTF-8");
} finally {
IOUtils.closeQuietly(is);
}

Related

Writing from Stream<String> to PrintWriter drops lines [duplicate]

For some reason my String is written partially by PrintWriter. As a result I am getting partial text in my file. Here's the method:
public void new_file_with_text(String text, String fname) {
File f = null;
try {
f = new File(fname);
f.createNewFile();
System.out.println(text);
PrintWriter out = new PrintWriter(f, "UTF-8");
out.print(text);
} catch (IOException e) {
e.printStackTrace();
}
}
Where I print text to a console, I can see that the data is all there, nothing is lost, but apparently part of text is lost when PrintWriter does its job... I am clueless..
You should always Writer#close your streams before you discard your opened streams. This will free some rather expensive system resources that your JVM must quire when opening a file on the file system. If you do not want to close your stream, you can use Writer#flush. This will make your changes visible on the file system without closing the stream. When closing the stream, all data is flushed implicitly.
Streams always buffer data in order to only write to the file system when there is enough data to be written. The stream flushes its data automatically every now and then when it in some way considers the data worth writing. Writing to the file system is an expensive operation (it costs time and system resources) and should therefore only be done if it really is necessary. Therefore, you need to flush your stream's cache manually, if you desire an immediate write.
In general, make sure that you always close streams since they use quite some system resources. Java has some mechanisms for closing streams on garbage collection but these mechanisms should only be seen as a last resort since streams can live for quite some time before they are actually garbage collected. Therefore, always use try {} finally {} to assure that streams get closed, even on exceptions after the opening of a stream. If you do not pay attention to this, you will end up with an IOException signaling that you have opened too many files.
You want to change your code like this:
public void new_file_with_text(String text, String fname) {
File f = null;
try {
f = new File(fname);
f.createNewFile();
System.out.println(text);
PrintWriter out = new PrintWriter(f, "UTF-8");
try {
out.print(text);
} finally {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Try to use out.flush(); right after the line out.print(text);
Here is a proper way to write in a file :
public void new_file_with_text(String text, String fname) {
try (FileWriter f = new FileWriter(fname)) {
f.write(text);
f.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
I tested you code. You forgot to close the PrintWriter object i.e out.close
try {
f = new File(fname);
f.createNewFile();
System.out.println(text);
PrintWriter out = new PrintWriter(f, "UTF-8");
out.print(text);
out.close(); // <--------------
} catch (IOException e) {
System.out.println(e);
}
You must always close your streams (which will also flush them), in a finally block, or using the Java 7 try-with-resources facility:
PrintWriter out = null;
try {
...
}
finally {
if (out != null) {
out.close();
}
}
or
try (PrintWriter out = new PrintWriter(...)) {
...
}
If you don't close your streams, not only won't everything be flushed to the file, but at some time, your OS will be out of available file descriptors.
You should close your file:
PrintWriter out = new PrintWriter(f, "UTF-8");
try
{
out.print(text);
}
finally
{
try
{
out.close();
}
catch(Throwable t)
{
t.printStackTrace();
}
}

Is it necessary to call close() in a finally when writing files in Java?

There are a few examples where people call close() in their finally block when writing to a file, like this:
OutputStream out = null;
try {
out = new FileOutputStream(file);
out.write(data);
out.close();
}
catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
}
But there are many more examples, including the official Android docs where they don't do that:
try {
OutputStream out = new FileOutputStream(file);
out.write(data);
out.close();
}
catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
Given that the second example is much shorter, is it really necessary to call close() in finally as shown above or is there some mechanism that would clean up the file handle automatically?
Every situation is a little bit different, but it's best to always close in a finally block OR use java's try with resources syntax, which is effectively the same thing.
The risk you run by not closing in the finally block is that you end up with an unclosed stream object after the catch gets triggered. Also, if your stream is buffered, you might need that final close to flush the buffer to ensure that the write is fully complete. It may be a critical error to complete without that final close.
Not closing the file may mean the stream contents don't get flushed in a timely way. This is a concern in the case that the code completes normally and doesn't throw an exception.
If you don't close a FileOutputStream, then its finalize method will try to close it. However, finalize doesn't get called immediately, it is not guaranteed to get called at all, see this question. It would be better not to rely on this.
If JDK7's try-with-resources is an option then use it:
try (OutputStream out = new FileOutputStream(file);) {
out.write(data);
}
Otherwise, for JDK6, make sure the exception thrown on close can't mask any exception thrown in the try block:
OutputStream out = new FileOutputStream(file);
try {
out.write(data);
} finally {
try {
out.close();
} catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
}
It may be verbose but it makes sure the file gets closed.
Yes, it is. Unless you let someone else manage that for you.
Some solutions for that:
Java try-with-resources (from Java 7 / API Level 19)
Guava Sources and Sinks (has a nice explanation)
It is very important it always close when are writing to or reading a file because if you don't close the writer or the reader. You won't be able to write to a file unless you have the reader closed and vice versa.
Also if you don't close, you might cause some memory leaks. Always remember to close whatever you have open. It doesn't hurt to close, if anything it makes your code more efficient.

Why does my program stop running and does not return error?

I put the declaration in the while loop, and the program would not running and also does not return any error. I suspect the while loop become an infinite loop.
try
{
while (true)
{
inputStream = new ObjectInputStream (new FileInputStream (fileName));
Ship copyObject = (Ship) inputStream.readObject();
String nameCompany = copyObject.getCompanyName();
if (compName.equalsIgnoreCase(nameCompany)){
listShipName += (copyObject.getShipName() + ", ");
numberOfShip ++;
}
}
}
catch (EOFException e)
{
}
catch (Exception e)
{
e.printStackTrace();
}
But if I put the declaration of input stream out of the while loop, the program runs successfully. Can someone explain why this happens?
try
{
inputStream = new ObjectInputStream (new FileInputStream (fileName));
}
catch (Exception e)
{
e.printStackTrace();
}
try
{
while (true)
{
Ship copyObject = (Ship) inputStream.readObject();
String nameCompany = copyObject.getCompanyName();
if (compName.equalsIgnoreCase(nameCompany)){
listShipName += (copyObject.getShipName() + ", ");
numberOfShip ++;
}
}
}
catch (EOFException e)
{
}
catch (Exception e)
{
e.printStackTrace();
}
You're reopening your file on every iteration through the loop, which means you are only ever reading the first object from the file. But you're reading the same object over and over again.
As well as opening your file only once, you really should try to detect the end of file without throwing an exception. As a matter of style, exceptions should be thrown when things go wrong, not as a matter of course.
Now I realize that in each iteration, I reopen the input stream, so the loop would not reach to the end of the file, and it becomes infinite.

Sending output to external process

For some reason, I'm having problems sending output to a process that I've created in Java. The external process is running in a command prompt, and the peculiar thing is that I can click that, type, hit enter, and I'll get output from the program. It addition my program can read all the output coming from the program, it just can't send anything to it.
Anyways, here is the relevant code I'm using that just isn't working...
try {
ProcessBuilder builder=new ProcessBuilder(args);
builder.redirectErrorStream(true);
final Process p=builder.start();
// Process has been created and is running
try {
String b="";
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
final BufferedWriter output = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
new Thread(){public void run(){
// This thread will periodically send "get_time" to the process to get an update on its progress
while(true)
{
try {
Thread.sleep(1000);
p.exitValue();
// p.exitValue() only works when process has ended, so normal code goes in the catch block
output.close();
break;
// Leave the infinite loop if the program has closed
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
break;
// Leave the infinite loop if we tried closing our output stream, but it was already closed
} catch (InterruptedException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalThreadStateException e) {
try {
System.out.println("Outputted: get_time");
output.write("get_time" + System.lineSeparator());
output.flush();
// Give the process some input
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}}.start();
while((b = input.readLine()) != null){
System.out.println(new Time(System.currentTimeMillis()).toString() + " " + b);
// Log all output the process gives
}
input.close();
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
}
// More code here
} catch (IOException ex) {
Logger.getLogger(OvMusicUI.class.getName()).log(Level.SEVERE, null, ex);
}
If necessary, I can give an example command and the name of the external program being run so you can try it yourself...
Thanks!
EDIT: Here is an example of what's passed into the ProcessBuilder: Arrays.asList("VLC\vlc.exe", "-Irc", "-vvv", "http://www.youtube.com/watch?v=xfeys7Jfnx8", "--sout", "file/ogg:Untitled 1.ogg", "--play-and-exit", "--rc-quiet"). The only difference is I use absolute paths instead of relative paths. The program is VLC Media Player 2.0.7.
Your code has a few problems. First, you generally should not use exceptions for your regular control flow: it's expensive, it's difficult to read, and it makes handling actual errors more difficult. It's generally better to spawn another Thread that calls p.waitFor() and signals your main thread to complete, such as with wait/notify.
Also, your construction with the infinite loop and using break instead of return will make your code more difficult to debug; instead, use a Timer.
It looks like the output to your external program probably is working correctly but that the problem is just with reading its output. The program may be buffering its own output or may be detecting that it's not being run interactively and behaving differently.

Read/Write File in blackberry

I am writing to a file using this code.
protected void writeFile(String text) {
DataOutputStream os = null;
FileConnection fconn = null;
try {
fconn = (FileConnection) Connector.open("file:///store/home/user/documents/file.txt", Connector.READ_WRITE);
if (!fconn.exists())
fconn.create();
os = fconn.openDataOutputStream();
os.write(text.getBytes());
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
if (null != os)
os.close();
if (null != fconn)
fconn.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}}
the code is working fine.
My problem is if I write first time "Banglore" and when I read it, I get "Banglore".
But, second time when I write "India" and when I read it, I get, "Indialore".
so, basically its content is not changing according the text , I am giving.
Please tell me how to fix this.
writing in a file doesn't remove the content but it just replaces the content, so writing 'india' over 'Bangalore' will replace the 'Banga' with 'India' and the rest would remain the same. If you want to completely remove old content with newer one, you need to truncate()
the file from where the newer data ends. truncate(text.getBytes().length)

Categories