I'm trying to write a program where the user can: 1) Add a person to the contact (name, phone, email), 2) Remove a person from the contacts, 3) Read all from contact.
The Way I'm doing this is I'm asking for the user for their choice and respectively does whatever. For writing, I simply write an object to the file. For removing, I think I'll be asking the user for "last name" which will be used as the KEY (since I'm using a TreeMap)and will remove the value (object) at the key.
So I'm having a problem with reading here. I'm trying to read the object like so:
public void readContact()
{
TreeMap<String, Contact> contactMap = new TreeMap<String, Contact>();
try
{
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(
new FileInputStream(file)));
while( in.available() > 0 ) //This line does NOT read
{
Contact c = (Contact)in.readObject();
contactMap.put(c.getLastName(), c);
}
for(Map.Entry contact : contactMap.entrySet() )
{
Contact con = contactMap.get( contact.getKey() );
System.out.println( con.getLastName() + ", " + con.getFirstName() + ": " + con.getPhoneNumber() + "\t" + con.getEmail());
}
}
catch(Exception e)
{
System.out.println("Exception caught");
}
}
Please do not suggest doing something like while(true)
until I get the EOFException
because:
- that isn't what exception handling is for I believe
- I still have more things to do after this so I can't have the program terminating'
You can write the last object as null. And then iterate till you get a null at the reading side. e.g.
What you have discovered
You found out about
FileInputStream.available()
returning 0 even though there are unread bytes in the file! Why is this? This could happen (renderingFileInputStream.available()
unreliable for a couple of reasons:FileInputStream.available()
approximates the number of bytes that can be read without blockingFileInputStream
might be blockedSome alternative way
As an alternative to relying on EOFException to close the file, you could use a (very-small!) binary file that keeps track of the number of Objects in your file. (Judging from your code, it looks like you are simply writing Objects to the file.) The way I have used this is just to
For example, the first time the serialization file is created, I could make the binary file store
1 1
(which specifies that the number of Objects in the serialization file takes up 1 byte, and that number is 1). This way, after 255 Objects (remember, an unsigned byte can only store up to 28-1 == 255), if I write another Object (Object number 256 up to 2562-1 == 65535), the binary file will have, as contents,2 1 0
, which specifies that the number takes up 2 bytes and is 1*2561+0 == 256. Provided that the serialization is reliable (good luck on ensuring that: http://www.ibm.com/developerworks/library/j-serialtest/index.html), this method will let you store (and detect) up to 256255-1 bytes (which pretty much means that this method works indefinitely).The code itself
How something like that would be implemented would be something like:
Now, we have the number of Objects in the file (I leave it to you to figure out how to update the bytes to indicate that one more Object has been written when
yourOutputStream
callswriteObject(yourObject);
; I have to go clock in.)Edit:
yourOutputStream
is either going to write over all the data in thebinaryFile
or append data to it. I just found out thatRandomAccessFile
would be a way to insert data into anywhere in the file. Again, I leave details to you. However you want to do it.I know that you are looking for an answer that is not using exception handling, but I believe in this case using
EOFException
to determine when all input has been read is the right way.The JavaDoc of EOFException states that
So, there are input streams that use other means to signal an end of file, but
ObjectInputStream#readObject
usesObjectInputStream$BlockDataInputStream#peekByte
to determine if there is more data to read, andpeekByte
throws anEOFException
when the end of the stream has been reached.So it is feasible to use this exception as an indicator that the end of the file has been reached.
To handle the exceptions without interrupting the program flow, some of the possible exceptions should be passed up in the hierarchy. They can be handled by a
try - catch
block in the code that callsreadContact()
.The
EOFException
can simply be used as an indicator that we are done reading the objects.EOFException
would be a reasonable approach in your situation. CatchingEOFExcepion
will not terminate your program.ObjectOutputStream.writeInt
, and then you would read this number withObjectInputStream.readInt
and know how many objects to readnull
as EOF marker.readObject
.Why so much trouble while reading object from file, just save a hash map into a file and read the same once from file then perform any operation.
Also I would suggest to use any one of object oriented database like Db4o to do this quickly then you never worry about end of file exception
-
Exceptions
are not only used in order to raise an alarm when something goes wrong while calling a method, but are also used inThreads
andIO
with various other uses.- You can use
Exception
to indicate end of the file.- Use the
try-catch
combo to work along with the above to keep the flow of the program smooth.