How does Java know the types of objects and data when reading them back from a file

Hi I am new to Java and learning, I have searched for an answer to this question here and googled it, looked at the Java Doc but cant seem to find a clear explanation on exactly this topic.

When wrapping streams and Serializable objects, writing a mix of objects, data, primitives to a file, then reading them back again the data, objects, primitives must be read back exactly in same sequence as it was written. If there is mismatch in type or wrong sequence you get EOFException.

How does Java know the types of objects and data when reading back the file? I can only conclude this is stored in the file, or maybe the FileDescriptor? But there is nothing about this in the Java docs? or is there?

EDIT: I have tested this (Java 8) and I get a EOFException if I have the wrong sequence, and I get the Exception just at the start of reading the file.

EDIT2: Sorry I did not post the code, kind of lost it because I did many different stream writing and reading and got EOFException on several occasions when starting to read the file, correcting the type errors took away the exception. Code as follows, had to recreate from memory.

try (DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)))) {

        for (int i = 0; i < prices.length; i++) {
            dataOut.writeDouble(prices[i]);
            dataOut.write(numbers[i]);
            dataOut.writeUTF(desc[i]);
        }

 try (DataInputStream dataIn = new DataInputStream(new BufferedInputStream(
            new FileInputStream(dataFile)));) {
        double price;
        int number;
        String description;
        int c = 0;
        while (true) {
            price = dataIn.readDouble();
            number = dataIn.readInt();
            description = dataIn.readUTF();
            System.out.println(price + " " + number + " " + description);

I have omitted some code but the core elements are there, so the readInt method produces a EOFException, (write method used, not writeInt). If i correct the error (change to writeInt) everything runs fine. However if I swap places between price and number when reading there was no error and printed out rubbish, but still completed normally.

while (true) {
            description = dataIn.readUTF();
            price = dataIn.readDouble();
            number = dataIn.readInt();

But if I move the readUTF when reading the file I yet again get EOFException.

Jon Skeet
people
quotationmark

If there is mismatch in type or wrong sequence you get EOFException.

No, that's simply not true - at least not in the general case. You'll get an EOFException if you reach the end of the data too early. If you just read the data with the wrong methods, but still read the same amount of data (e.g. calling readInt twice instead of readLong once) you'll get useless data, but no exception. (There are exemptions to this - if you use readUTF you'll get an exception if the data isn't valid modified UTF-8 for example. Or readUTF could throw an EOFException if the length prefix says that the string is longer than the data in the stream - again, that's a matter of reading past the end of the stream.)

Here's a complete example:

import java.io.*;

public class Test {
    public static void main(String[] args) throws IOException {
        byte[] data;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            try (DataOutputStream dos = new DataOutputStream(baos)) {
                dos.writeLong(123456789012345L);
            }
            data = baos.toByteArray();
        }

        try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
            try (DataInputStream dis = new DataInputStream(bais)) {
                System.out.println(dis.readInt()); // 28744
                System.out.println(dis.readInt()); // -2045911175
            }
        }
    }
}

Note that when using ObjectOutputStream, when you call writeObject that does write the type name as part of the data, so that when you call readObject it knows what kind of object to create. However, the primitive reading/writing methods (such as the ones used above) still don't leave any indication of the type of data. Changing DataObjectStream/DataInputStream to ObjectOutputStream/ObjectInputStream in the above code doesn't change the result.

If you call readObject, and the stream is placed at the start of object data, it still won't throw EOFException - it will just read the correct kind of object, and if you cast it to the wrong type you'll get a ClassCastException. (There's no way of saying "I expect to read a Foo now.") If you call readObject and the stream isn't placed at the start of object data, then any number of odd things might happen, based on what data is present there.

You would only get an EOFException if you tried to read past the end of the data, however you did so - e.g. writing a long and then reading three int values.

As an example of how readUTF could cause an EOFException, consider this code:

import java.io.*;

public class Test {
    public static void main(String[] args) throws IOException {
                byte[] data;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            try (DataOutputStream dos = new DataOutputStream(baos)) {
                dos.writeShort(10000);
                for (int i = 0; i < 500; i++) {
                    dos.write(0);
                }
            }
            data = baos.toByteArray();
        }

        try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
            try (DataInputStream dis = new DataInputStream(bais)) {
                System.out.println(dis.readUTF());
            }
        }
    }
}

We start off writing the short value 10000, then we write 500 other bytes. When we call readUTF, that will read the value of 10000, and then expect to be able to read 10000 more bytes, because that's the format readUTF expects (length, data). That will fail with an EOFException because there isn't enough data. If you change writeShort(10000) to writeShort(100) then the exception goes away - even though you're still not matching writes with reads.

people

See more on this question at Stackoverflow