I have to read a series of object from a binary file.
I use:
ObjectOutputStream obj = new ObjectOutputStream(new FileInputStream(fame));
obj.readObject(p);
where p is a reference to an object I had created. How can I read the entire file until the end?
I can use:
while(p!=null){}
?
readObject() returns null if and only if you wrote a null. The correct technique is to catch EOFException and when you get it close the stream and exit the reading loop.
Let's assume you meant ObjectInputStream and p = obj.readObject().
I would do something like this: (this is wrong, see EDIT below)
FileInputStream fstream = new FileInputStream(fileName);
try {
ObjectInputStream ostream = new ObjectInputStream(fstream);
while (ostream.available() > 0) {
Object obj = ostream.readObject();
// do something with obj
}
} finally {
fstream.close();
}
EDIT
I take it back! EJP rightly points out that the use of available() is incorrect here. I think the fixed code might be:
FileInputStream fstream = new FileInputStream(fileName);
try {
ObjectInputStream ostream = new ObjectInputStream(fstream);
while (true) {
Object obj;
try {
obj = ostream.readObject();
} catch (EOFException e) {
break;
}
// do something with obj
}
} finally {
fstream.close();
}
Although the documentation for readObject() doesn't explicitly say that EOFException is thrown at the end of the stream, it seems to be implied and may be the only way to detect the end of the stream.
Another option if you control the code that wrote the stream would be to write an object count at the beginning, or a flag after each object indicating whether the previous object was the final one.
If you want to read object into your program, then you have to use ObjectInputStream, not ObjectOutputStream.
And if you will store a bunch of objects, then use an appropriate Collection for writing to file and reading from it. The API documentation for readObject does not state that it will return null or throw an exception if EOF is reached. So to be on the safe side, use Collections.
You may also want to read API docs on ObjectInputStream and ObjectOutputStream.
Boolean i = true;
while(i) {
try {
System.out.println(reader.readObject());
} catch(Exception e) {
i = false;
System.out.println("Dead end");
}
}
Guava's Files.toByteArray does what you want so if fame in your code is a File, then
import com.google.common.io.Files;
...
byte[] fameBytes = Files.toByteArray(fame);
Related
Currently writing an application like Booking and I am in the stage where i want to store my infomation in files. I have created a Serializable Database class which has a field with a pathname and 2 methods for read/write . I have about 8 other classes which extend the Database and each holds a Hashmap and some querying methods. Naturally I read the Databases from my files before i start the application and i write before exiting, but I ran into a problem where the objects I am reading are all null. I've been at it for 2 hours now and I need a second opinion. This is the database's read/write methods:
public void write() {
try {
File temp = new File(this.filename);
temp.createNewFile(); // create file if not present
FileOutputStream fileOut = new FileOutputStream(this.filename);
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(this);
objectOut.close();
System.out.println("The Object was successfully written to a file");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public Object read() {
Object obj = null;
try {
File temp = new File(this.filename);
temp.createNewFile(); // create file if not present
FileInputStream fileIn = new FileInputStream(this.filename);
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
obj = objectIn.readObject();
System.out.println("The Object was successfully read from the file");
objectIn.close();
} catch (EOFException ex) {
return obj;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
And here is the way I load them (Which is probably the problem) in my Application class
private void loadData() {
accommodationReviewsDatabase = (AccommodationReviews) accommodationReviewsDatabase.read();
brokerAccommodationsDatabase = (BrokerAccommodations) brokerAccommodationsDatabase.read();
credentialsUserDatabase = (CredentialsUser) credentialsUserDatabase.read();
customerReviewsDatabase = (CustomerReviews) customerReviewsDatabase.read();
userConfirmationsDatabase = (UserConfirmations) userConfirmationsDatabase.read();
userMessagesDatabase = (UserMessages) userMessagesDatabase.read();
}
private void writeData() {
accommodationReviewsDatabase.write();
brokerAccommodationsDatabase.write();
credentialsUserDatabase.write();
customerReviewsDatabase.write();
userConfirmationsDatabase.write();
userMessagesDatabase.write();
}
Some extra information that may be asked :
All my classes that I am storing are serializable
The files I am storing the databases are all *.ser (Thats the extension I found)
The files are stored inside the project
If your read() method completes without an EOFException, it ends with return null;. You should return obj;, the object you read.
You should not expect that EOFException will be thrown if your read succeeds. The EOFException would indicate that it ran out of data while it was trying to read your object, and could not complete successfully.
If you do get an EOFException, it is probably a good idea to give some indication instead of silently returning. Silent catch blocks deny you information that could be useful for debugging.
This question already has an answer here:
Why is ObjectInputStream readObject() throwing EOF exception
(1 answer)
Closed 7 years ago.
So, I write an object to a client like so:
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
out.writeObject(args);
out.close();
And receive the object on the client side like so:
ObjectInputStream in = new ObjectInputStream(connection.getInputStream());
Object objIn;
while(true) {
if((objIn = in.readObject()) != null) {
//work with obj
}
}
I never create an output stream on the client side or an input stream on the server side.
Also, the object I send is serializable.
Thanks for you help!
EDIT: The "duplicate" of this question doesn't help me answer my problem, so this one is not a duplicate.
while(true) {
if((objIn = in.readObject()) != null) {
//work with obj
}
}
Q. Why are you testing for null? Are you planning on sending a null? Because that's the only time you'll ever get one.
A. Because you think readObject() returns null at end of stream. Although you've left out the break that would escape the infinite loop.
It doesn't. It throws EOFException. So your loop should look like this:
try
{
while(true) {
objIn = in.readObject();
//work with obj
}
}
catch (EOFException exc)
{
// end of stream
}
finally
{
in.close();
}
Assuming you received the exception while reading the input stream from connection Object .
If you already invoked the connection.getInputStream() prior to the above cited code for input stream you will receive a EOF exception . Because the input Stream in the connection object is already consumed .
related topic
One solution to such problem is to write the content of the input stream in a Random access file as they enables you to traverse through the file .
public static RandomAccessFile toRandomAccessFile(InputStream is, File tempFile) throws IOException
{
RandomAccessFile raf = new RandomAccessFile(tempFile, "rwd");
byte[] buffer = new byte[2048];
int tmp = 0;
while ((tmp = is.read(buffer)) != -1)
{
raf.write(buffer, 0, tmp);
}
raf.seek(0);
return raf;
}
Later you can always read from the file as follows .
public static InputStream toInputStream(RandomAccessFile file) throws IOException
{
file.seek(0); /// read from the start of the file
InputStream inputStream = Channels.newInputStream(file.getChannel());
return inputStream;
}
I currently have a working parser. It parses a file once(not what I want it to do) and then outputs parsed data into a file. I need it to keep parsing and appending to the same output file until the end of the input file. Looks something like this.
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Everything is done except the while loop. It only parses once when I need it to keep parsing. I'm looking for a while loop function to reach eof.
I'm also using a DataInputStream. Is there some sort of DataInputStream.hasNext function?
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
i.e. dis.read();
.
//Need a while !eof while loop
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Warning: This answer is incorrect. See the comments for explanation.
Instead of looping until an EOFException is thrown, you could take a much cleaner approach, and use available().
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
while (dis.available() > 0) {
// read and use data
}
Alternatively, if you choose to take the EOF approach, you would want to set a boolean upon the exception being caught, and use that boolean in your loop, but I do not recommend it:
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
boolean eof = false;
while (!eof) {
try {
// read and use data
} catch (EOFException e) {
eof = true;
}
}
DataInputStream has a lot of readXXX() methods that do throw EOFException but the method that you're using DataInputStream.read() does not throw EOFException.
To correctly identify the EOF while using read() implement your while loop as follows
int read = 0;
byte[] b = new byte[1024];
while ((read = dis.read(b)) != -1) { // returns numOfBytesRead or -1 at EOF
// parse, or write to output stream as
dos.write(b, 0, read); // (byte[], offset, numOfBytesToWrite)
}
If you are using FileInputStream, here's an EOF method for a class that has a FileInputStream member called fis.
public boolean isEOF()
{
try { return fis.getChannel().position() >= fis.getChannel().size()-1; }
catch (IOException e) { return true; }
}
When loading huge files with ObjectInputStream, all read objects are buffered by stream for object graph resolving.
This cause huge memory overhead which isn't needed in my case (all objects read are interdependent).
Is there an equivalent to the reset() method of ObjectOutputStream which reset this buffer?
Code example:
try (FileInputStream fileInputStream = new FileInputStream(filename);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
ObjectInputStream objectInputStream = new ObjectInputStream(bufferedInputStream)) {
while (object = objectInputStream.readObject()) {
System.Out.println(object.toString());
}
}
There is actually a reset method on the class but it does a complete different thing.
See Java APIs which cause memory bloat
It's up to the sender to decide when to break the integrity of sent object graphs, by calling ObjectOutputStream.reset(). Not the receiver.
NB your code doesn't compile, and wouldn't be valid if it did:
while (object = objectInputStream.readObject()) {
}
This should be
try {
while (true) {
object = objectInputStream.readObject();
// ...
}
}
catch (EOFException exc) {
// end of stream
}
There is a misconception abroad that readObject() returns null at end of stream. It doesn't. It throws EOFException. It can return null any time you wrote a null.
Hmm it seems you need to use some sort of lazy loading techniques where you only load necessairy components of the object graph, not everything.
I want to create two methods. The one should store and arraylist to the cache and the other should retrieve the arraylist from the cache. The code that I've tried is the following:
public class ByteConverter<T> {
public byte[] write_to_byte_array(ArrayList<T> list,File file){
// write to byte array
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e1) {
Log.d("file not found", "file not found", e1);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
for (T element : list) {
try {
out.writeUTF((String) element);
} catch (IOException e) {
Log.d("Error converting List to byte array", "Error converting List to byte array", e);
}
}
byte[] bytes = baos.toByteArray();
int len1 = 0;
while (len1 < bytes.length) {
try {
fos.write(bytes, 0, len1);
len1++;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
public String read_to_byte_array(byte[] bytes) throws IOException{
// read from byte array
String element = null;
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
DataInputStream in = new DataInputStream(bais);
while (in.available() > 0) {
element = in.readUTF();
}
return element;
}
}
However the aforementioned methods doesn't write anything to the file. I don't know why. Can anyone help me? Also I'm taking a ClassCastException at this line:
out.writeUTF((String) element);
First, the ClassCastExcetion is the reason you are not getting any output. The exception is thrown before your code writes to the file ...
Second, the ClassCastException is happening because the element is not a String. In theory, you could call element.toString() to get a string representation, but the chances are that that representation will NOT be suitable for your purpose.
So what is the correct approach?
Well it depends on the types of the objects in list.
If they implement Serializable (or Externalizable) then you should be able to use Java serialization. Read this section of the Java tutorial for more details.
Another option might be to use something like JAXP or GSON which can serialize POJOs to XML and JSON respectively.
The final fallback is to code the serialization method (and a corresponding serialization method) by hand.
Finally, I should point out some other errors in your code:
1) This code is wrong:
int len1 = 0;
while (len1 < bytes.length) {
fos.write(bytes, 0, len1);
len1++;
}
This will write:
bytes[0]
bytes[0], bytes[1]
bytes[0], bytes[1], bytes[2]
and so on.
The correct way to write bytes is:
fos.write(bytes);
or
fos.write(bytes, 0 bytes.length);
2) Your exception handling logic is incorrect. In 3 or 4 places you catch an exception, print or log something ... and then continue as if nothing had gone wrong. What you should probably do is let the exceptions propagate, and handle them at a higher level.
3) If something goes wrong in the write_to_byte_array method it is likely to leak a file descriptor. Best practice is to either close resources in a finally block, or use the new Java 7 try-with-resource syntax.
4) The names of the read_to_byte_array and write_to_byte_array methods violate the accepted Java style guidelines. They should be readToByteArray (or better still readFromByteArray) and writeToByteArray.
Rergarding ClassCastException, if element of type T isn't a String you will get that exception since that object cannot be casted to String. Maybe you are looking for toString method of element.
Also take a look to the FileUtils class of Apache Commons and the method writeLines
use Serializable Object , because ArrayList implement Serializable , must be implement Serializable.
youself can custom data type ,for example:
length|value|length|value....
4bytes|bytes|4bytes|bytes....