Files not writing, closing files, finalize()

M

Matt

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
 
A

Andrew Thompson

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?
 
J

Joshua Cranmer

Matt said:
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.
 
O

Owen Jacobson

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
 
A

Arne Vajhøj

Joshua said:
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
 
J

Joshua Cranmer

Arne said:
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.
 
A

Arne Vajhøj

Joshua said:
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.


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
 
A

Arne Vajhøj

Arne said:
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
 
J

J. Davidson

Joshua said:
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
 
J

J. Davidson

J. Davidson said:
Joshua said:
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?

Darn, no bold here? Oh well ...

- jenny
 
L

Lars Enderin

J. Davidson skrev:
J. Davidson said:
Joshua said:
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?

Darn, no bold here? Oh well ...
*Bold* works for me.
 
J

Joshua Cranmer

J. Davidson said:
Anyone want to know why there's two layers of buffering in Java?

This is not phpBB. This is Usenet, which is generally pure text. The
standard way of indicating boldness in pure text is with *a pair of
asterisks.*
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.

I'm not an expert as to where the buffering is, but I'm pretty sure the
call to the OS-level write routines are expensive in and of themselves.
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.

So? There's already high-level API buffering, filesystem buffering, and
probably disk-level buffering as well. As long as they can be reasonably
guarded against concurrency issues, there's no problem.
 
L

Lew

Lars said:
*Bold* works for me.

By design, Usenet is supposed to be usable in raw text mode. It is
bad form to embed HTML, so we use conventions like slash for /italics/
and asterisk for *bold*. Some newsreaders interpret those
conventions, and even grey out sigs set off by "dash dash space" ("--
") on a line by itself. That is up to the newsreader. The rest of us
do it by imagination.
 
L

Lew

Joshua Cranmer said:
So? There's already high-level API buffering, filesystem buffering, and
probably disk-level buffering as well. As long as they can be reasonably
guarded against concurrency issues, there's no problem.

"Disks are a hack."
- Alan Cooper, /About Face/

Disks are a hack because it's too expensive to buy a terabyte of
static RAM.

Fifty years from now hard disks will be obsolete.
 
J

Joshua Cranmer

Lew said:
Fifty years from now hard disks will be obsolete.

Predictions of obsolescence tend to be woefully underestimated. After
all, the magnetic tape has not died its death yet.

I predict that fifty years from now, some people will be using hard
disks, by necessity. It may evolve into a niche role (like magnetic
tape), but it will still have one nonetheless.
 
R

Roedy Green

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?
}

Looks ok. Try being more explicit where the file is written by
specifying drive and dir. Dump out the CWD, it may not be where you
expect. That it where test.txt will show up.

Also try a println not print. Your editor you using to look at the
file might not be happy with the missing terminator.

Even if the file were to close eventually automatically, you want to
release the considerable resources for it as soon as possible.

See http://mindprod.com/jgloss/finalize.html There in no guarantee
finalizers will ever be run.

--
Roedy Green Canadian Mind Products
http://mindprod.com
Your old road is
Rapidly agin'.
Please get out of the new one
If you can't lend your hand
For the times they are a-changin'.
 
M

Martin Gregorie

"Disks are a hack."
- Alan Cooper, /About Face/

Disks are a hack because it's too expensive to buy a terabyte of static
RAM.

Fifty years from now hard disks will be obsolete.

....only if somebody designs reliable non-volatile RAM with either a multi-
decade storage and read-only lifetime or at least a million-fold increase
in the number of write cycles it can handle without failing.
 
T

Tom Anderson

...only if somebody designs reliable non-volatile RAM with either a multi-
decade storage and read-only lifetime or at least a million-fold increase
in the number of write cycles it can handle without failing.

Wrong. Because tape's going to make a comeback - I GUARANTEE IT!

tom
 
L

Lew

Martin said:
...only if somebody designs reliable non-volatile RAM with either a multi-
decade storage and read-only lifetime or at least a million-fold increase
in the number of write cycles it can handle without failing.

Or they develop a different form of offline storage with better
performance than hard drives and higher capacity, which I deem
extremely likely. RAM and hard drives are not the only two ways to
store data even today, so I figure other technologies are just around
the corner, and that doesn't even account for ideas not yet
conceived. Fifty years is eons of innovation in I.T. and electronics.

I have yet to have a hard drive last one decade, much less multiple
decades, so that part of the argument leaves me cold. I know of no
serious project that doesn't back up its hard drives, so I figure my
experience isn't unique.

So I take exception to the "only if" part of your argument.
Additionally, someone very well might come up with "reliable non-
volatile RAM with either a multi-decade storage and read-only lifetime
[which would then be better than hard drives are now][,] or at least a
million-fold increase in the number of write cycles it can handle
without failing."

So far no electronic medium exceeds the read-only lifetime of ink on
paper.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top