Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Files not writing, closing files, finalize()

Reply
Thread Tools

Files not writing, closing files, finalize()

 
 
Matt
Guest
Posts: n/a
 
      11-16-2008
Can somebody explain to me why file output doesn't work unless the
file is closed explicitly?

{
PrintWriter pw = new PrintWriter(new File("test.txt"));
pw.print("Hello world!");
pw.close(); // necessary?
}

Shouldn't files be closed by the OS when the program ends? If so, why
doesn't the file ever get written?

I tried making my own class which closes the file in finalize(), but
that doesn't necessarily get called either, so that's out. There's no
other destructor type of thing in Java.

I just don't understand why Java can't close the file for me. All
other languages do it and this is supposed to be a high level
language. It actually acts like the file was never opened for writing
at all. It might truncate the file to 0 bytes, but it never writes
data to the file unless you manually close it. Can anyone explain why
the behavior is like this?

Matt
 
Reply With Quote
 
 
 
 
Andrew Thompson
Guest
Posts: n/a
 
      11-16-2008
On Nov 17, 10:12*am, Matt <(E-Mail Removed)> wrote:
> Can somebody explain to me why file output doesn't work unless the
> file is closed explicitly?
>


try

> {
> * * * * PrintWriter pw = new PrintWriter(new File("test.txt"));
> * * * * pw.print("Hello world!");


pw.flush();

> * * * * pw.close(); *// necessary?
>
> }


catch (...)

finally ...

> Shouldn't files be closed by the OS when the program ends? *


Of course files are 'closed' when the Java program
that had them loaded, has exited. No program has
them open, so they are closed.

>...If so, why
> doesn't the file ever get written?
>
> I tried making my own class which closes the file in finalize(), but
> that doesn't necessarily get called either, so that's out. *There's no
> other destructor type of thing in Java.
>
> I just don't understand why Java can't close the file for me. *All
> other languages do it and this is supposed to be a high level
> language. *It actually acts like the file was never opened for writing
> at all. *It might truncate the file to 0 bytes, but it never writes
> data to the file unless you manually close it. *Can anyone explain why
> the behavior is like this?


Java was designed for robustness, extensibility
and performance, rather than lazy programmers?

--
Andrew Thompson
http://pscode.org/
 
Reply With Quote
 
 
 
 
Joshua Cranmer
Guest
Posts: n/a
 
      11-16-2008
Matt wrote:
> Can somebody explain to me why file output doesn't work unless the
> file is closed explicitly?
>
> {
> PrintWriter pw = new PrintWriter(new File("test.txt"));
> pw.print("Hello world!");
> pw.close(); // necessary?
> }


The actual necessary step is "pw.flush()". If you're flushing, you don't
need the close. Note that "pw.close()" is actually performing a flush
for you.

> Shouldn't files be closed by the OS when the program ends? If so, why
> doesn't the file ever get written?


Because PrintWriter.close() flushes the stream first but the OS's
closing doesn't flush the stream.

> I tried making my own class which closes the file in finalize(), but
> that doesn't necessarily get called either, so that's out. There's no
> other destructor type of thing in Java.


Finalizers are evil. As you've discovered, they're not always called.
There are also numerous other problems. In short: eschew finalize() if
at all possible.

> I just don't understand why Java can't close the file for me. All
> other languages do it and this is supposed to be a high level
> language. It actually acts like the file was never opened for writing
> at all. It might truncate the file to 0 bytes, but it never writes
> data to the file unless you manually close it. Can anyone explain why
> the behavior is like this?


It's because you're using the API wrong. PrintWriter is a shell around a
generic Writer to make output easier. If you read the API, you'll notice
that it states that it buffers the output. The buffer is only guaranteed
to be committed when it is flushed; the default buffer size appears to
be 8 KiB, so your measly 10-character string isn't being flushed to the
output.

Constructing a FileOutputStream under default settings (internally
performed by the PrintWriter constructor you used) will truncate the
file, but it doesn't write the data until buffers are flushed (not
closed). Note that this feature is actually relatively common in
high-level languages, buffering output data. Remember that something
like disk access is actually very expensive, so buffering is a
tremendous boost in speed.

In short: it's not closing the file, it's flushing the stream when it's
actually written. It just appears to be the stream closure because
closure implies a final flush.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
Reply With Quote
 
Owen Jacobson
Guest
Posts: n/a
 
      11-16-2008
On Nov 16, 6:12*pm, Matt <(E-Mail Removed)> wrote:
> Can somebody explain to me why file output doesn't work unless the
> file is closed explicitly?
>
> {
> * * * * PrintWriter pw = new PrintWriter(new File("test.txt"));


Per the PrintWriter javadocs, this constructor creates a PrintWriter
with automatic flushing completely disabled: text is buffered in RAM
(internally, by a BufferedWriter) until a certain number of characters
are written. Nothing is written to the OS until the buffer is full,
flush() is called, or close() is called.

You're also missing this:
try {

> * * * * pw.print("Hello world!");


} finally {
> * * * * pw.close(); *// necessary?

}

The close is not only necessary, but so necessary that you should make
sure it's called on all possible code paths - even if pw.print throws
an exception. Hence the try/finally construct.
>
> }
>
> Shouldn't files be closed by the OS when the program ends? *If so, why
> doesn't the file ever get written?


The file is being closed by the OS. However, PrintWriter buffers
writes internally, either until println is called (for autoflush =
true) or until the buffer is full or flushed (for autoflush = false).
The OS has no idea that there's data pending, because your code never
tells it.

> I tried making my own class which closes the file in finalize(), but
> that doesn't necessarily get called either, so that's out. *There's no
> other destructor type of thing in Java.


Don't do this. Finalize is never guaranteed to be called and
overriding it slows down garbage collection for passes involving
finalizable objects.

> I just don't understand why Java can't close the file for me. *All
> other languages do it and this is supposed to be a high level
> language. *It actually acts like the file was never opened for writing
> at all. *It might truncate the file to 0 bytes, but it never writes
> data to the file unless you manually close it. *Can anyone explain why
> the behavior is like this?


The underlying FileOutputStream is automatically closed by
finalization, but none of the other intermediate streams (at last
count: PrintWriter -> BufferedWriter -> OutputStreamWriter ->
FileOutputStream) will do anything special when they're garbage-
collected. If you want to guarantee that things written to the
PrintWriter are written to the FileOutputStream, flush or close the
writer.

-o
 
Reply With Quote
 
Matt
Guest
Posts: n/a
 
      11-17-2008
Thanks for the replies, everyone. They were very informative.

Matt
 
Reply With Quote
 
Arne Vajh°j
Guest
Posts: n/a
 
      11-17-2008
Joshua Cranmer wrote:
> Matt wrote:
>> Can somebody explain to me why file output doesn't work unless the
>> file is closed explicitly?
>>
>> {
>> PrintWriter pw = new PrintWriter(new File("test.txt"));
>> pw.print("Hello world!");
>> pw.close(); // necessary?
>> }

>
> The actual necessary step is "pw.flush()". If you're flushing, you don't
> need the close. Note that "pw.close()" is actually performing a flush
> for you.


Is it ?

close will flush the Java buffer and call OS close - and OS close
will flush OS buffer. It seems very likely to work.

flush will flush the Java buffer and image termination will
implicit close the file. But is is guaranteed that a image
termination implicit close will flush the OS buffer ? I would
have guessed that to be highly OS specific.

Arne
 
Reply With Quote
 
Joshua Cranmer
Guest
Posts: n/a
 
      11-17-2008
Arne Vajh°j wrote:
> Joshua Cranmer wrote:
>> The actual necessary step is "pw.flush()". If you're flushing, you
>> don't need the close. Note that "pw.close()" is actually performing a
>> flush for you.

>
> Is it ?
>
> close will flush the Java buffer and call OS close - and OS close
> will flush OS buffer. It seems very likely to work.


By "flushing," I mean from the Java API. Even if the OS is buffering
(which it most likely is), if the Java does not flush it to the native
system--which is clearly what is happening here--the OS doesn't see
anything when it foes to flush.

> flush will flush the Java buffer and image termination will
> implicit close the file. But is is guaranteed that a image
> termination implicit close will flush the OS buffer ? I would
> have guessed that to be highly OS specific.


I don't profess to be an expert in filesystems, but for the average
user, an OS flush or close will cause the changes it sees to be
committed so that it is visible externally. The reality is probably much
more convoluted.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
Reply With Quote
 
Arne Vajh°j
Guest
Posts: n/a
 
      11-17-2008
Joshua Cranmer wrote:
> Arne Vajh°j wrote:
>> Joshua Cranmer wrote:
>>> The actual necessary step is "pw.flush()". If you're flushing, you
>>> don't need the close. Note that "pw.close()" is actually performing a
>>> flush for you.

>>
>> Is it ?
>>
>> close will flush the Java buffer and call OS close - and OS close
>> will flush OS buffer. It seems very likely to work.

>
> By "flushing," I mean from the Java API. Even if the OS is buffering
> (which it most likely is), if the Java does not flush it to the native
> system--which is clearly what is happening here--the OS doesn't see
> anything when it foes to flush.
>
>> flush will flush the Java buffer and image termination will
>> implicit close the file. But is is guaranteed that a image
>> termination implicit close will flush the OS buffer ? I would
>> have guessed that to be highly OS specific.

>
> I don't profess to be an expert in filesystems, but for the average
> user, an OS flush or close will cause the changes it sees to be
> committed so that it is visible externally. The reality is probably much
> more convoluted.


I will not call myself an expert in that area either.

But calling close instead of flush in Java sounds much more safe
to me regarding getting the OS buffer written to the plates.

Arne
 
Reply With Quote
 
Arne Vajh°j
Guest
Posts: n/a
 
      11-17-2008
Arne Vajh°j wrote:
> Joshua Cranmer wrote:
>> Arne Vajh°j wrote:
>>> Joshua Cranmer wrote:
>>>> The actual necessary step is "pw.flush()". If you're flushing, you
>>>> don't need the close. Note that "pw.close()" is actually performing
>>>> a flush for you.
>>>
>>> Is it ?
>>>
>>> close will flush the Java buffer and call OS close - and OS close
>>> will flush OS buffer. It seems very likely to work.

>>
>> By "flushing," I mean from the Java API. Even if the OS is buffering
>> (which it most likely is), if the Java does not flush it to the native
>> system--which is clearly what is happening here--the OS doesn't see
>> anything when it foes to flush.
>>
>>> flush will flush the Java buffer and image termination will
>>> implicit close the file. But is is guaranteed that a image
>>> termination implicit close will flush the OS buffer ? I would
>>> have guessed that to be highly OS specific.

>>
>> I don't profess to be an expert in filesystems, but for the average
>> user, an OS flush or close will cause the changes it sees to be
>> committed so that it is visible externally. The reality is probably
>> much more convoluted.

>
> I will not call myself an expert in that area either.
>
> But calling close instead of flush in Java sounds much more safe
> to me regarding getting the OS buffer written to the plates.


Unless there is something in the contracts for Java flush and close
that I am not aware of. Which is absolutely a possibility.

Arne
 
Reply With Quote
 
J. Davidson
Guest
Posts: n/a
 
      11-17-2008
Joshua Cranmer wrote:
> Note that this feature is actually relatively common in
> high-level languages, buffering output data. Remember that something
> like disk access is actually very expensive, so buffering is a
> tremendous boost in speed.


Anyone want to know why there's two layers of buffering in Java?
It's not that Java doesn't trust the OS buffering. It's because each
trip through JNI to call an OS API routine is expensive.

So Java buffers because each JNI call is expensive. Then the OS buffers
because each disk write is expensive.

Another fifty years from now we'll probably have a big teetering tower
of abstractions and I/O will get buffered at six or seven layers instead
of just two.

Wait, make that three. I think most modern disk controllers do some
buffering of their own, because waiting for the right spot on a platter
to rotate under the write head is expensive, and waiting for the head to
move to a different cylinder is even more expensive.

- jenny
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
PyGame, window is not closing, tut not helping globalrev Python 3 05-13-2008 01:26 AM
Closing popup window when closing parent window? =?Utf-8?B?Vk1J?= ASP .Net 3 02-15-2007 08:29 AM
Closing the doors 15 minutes before closing. doofus Computer Support 12 06-11-2005 08:20 AM
Closing Files E Tepp Java 1 02-02-2004 08:35 PM
Closing child window WITHOUT closing parent thomas Javascript 0 10-23-2003 04:10 PM



Advertisments