Re: convenient way to read text file multiple times without reopening it
Without locking this will not work (at least not on Unix-like systems)=
=
and if
write lock does not restrain from file removal (which is write access =
to
directory, not the file), then even lock will not help.
Imagine this scenario:
- my program opens the file
- somebody else renames or removes the file (the file will disappear f=
rom
directory, but it's open file descriptors still work)
- optionally: another file with the same name is created
- I try to open the file with filename again, but either it does not =
exist or
is another file
I have a vague memory in Windows that when you force deletion of an open=
=
file, it will invalidate the file descriptors. Thus even if you have a =
stream created, reads after the point of deletion will throw an =
IOException.
If you really need to be able to reproduce a read, you might consider =
using File.createTempFile, copy the source to the temp, and then just =
re-read from temp file, since the probability of other apps mucking with=
=
temp files might be somewhat lower.
It may also be possible (I haven't tried this but it's a fairly easy =
=
test)
to open your file as a FileInputStream, get the stream's FileChannel =
and
then reset the position of that channel.
I just tried it and it works when I am reading from that FileInputStre=
am,
but not when I create InputStreamReader from that FileInputStream.
Here is my code:
public static void main(String[] args) throws IOException{
FileInputStream is = new FileInputStream("input");
FileChannel fc = is.getChannel();
InputStreamReader reader = new InputStreamReader(is);
for(int j=0;j<2;++j){
for(int i=0; i<5; ++i){
int x = is.read(); /* (X) */
if(x==-1)
System.exit(1);
System.out.print((char) x);
}
fc.position(0);
}
}
File "input" contains text "0123456789".
When I run this program, it outputs
"0123401234" as expected.
But when I change the line marked with /* (X) */ to
int x = reader.read();
then I get this output:
"0123456789", so the fc.position(0) had no effect.
Maybe there is some buffering in InputStreamReader,
but that I would expect only from BufferedReader.
Think of InputStreamReader as a bridge from byte[] to char[]. =
BufferedReader provides the decoded char buffer (char[]), but the =
InputStreamReader is still responsible for the binary reading, and thus =
it =
does maintain it's own private byte[] buffer.
When it comes to streams, once you wrap one stream with another stream, =
=
any further direct changes to the underling stream (without going throug=
h =
the outer stream first) usually result in "undefined" behavior of the =
outer stream. Thus, it's usually best to avoid making such changes.
For your case, if you are using NIO, you can use CharsetDecoder. You =
should be able to create your own ByteBuffer and CharBuffer, and use =
FileChannel.position + CharsetDecoder.reset to reset yourself back to a =
=
state. Alternatively, you might use =
java.nio.channels.Channels.newReader( <your FileChannel>, <your =
CharsetDecoder> ): just use the postion + reset on the channel + decoder=
=
and throw away the Reader without closing it - eventually closing the =
channel when you are done.
HTH,
-Zig