I want to use a single ObjectInputStream to read from a byte array, but I keep getting a StreamCorruptedException every time I start the program.
public void run(){
byte[] receiveBuffer = new byte[65535];
bIn = new ByteArrayInputStream(receiveBuffer);
try {
in = new ObjectInputStream(bIn);
} catch (IOException e1) {
e1.printStackTrace();
}
while(true){
try {
packetIn = new DatagramPacket(receiveBuffer, receiveBuffer.length);
sock.receive(packetIn);
Object o = in.readObject();
//do things with o
}
}
}
I'm just trying to initialize the ObjectInputStream to read from the byte array eventually, but it's throwing that exception even if I remove the while loop.
What am I doing wrong here?
If you take a look at the javadocs for the ObjectInputStream(InputStream) constructor, you'll see:
Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.
...
throws
StreamCorruptedException - if the stream header is incorrect
(emphasis added)
In other words, the constructor doesn't just record the InputStream reference you give it, it also reads from that object. In this case, that's a stream of all 0s.
You should defer creating the ObjectInputStream until you have the serialized data (or at least enough of it to read the header).
(In the interest of "teach a person to fish," I'll also note that any time a method/constructor throws an exception you don't expect, that method's javadocs are a good place to start for understanding its behavior. The javadocs for the JDK classes are usually pretty good.)
Ok, this is how object streams work and the solution that works everywhere.
Object stream data is preceded by a 4 byte 'magical' sequence AC ED 00 05. An ObjectInputStream will peek for this data at construction time rather than before the first read. And that's logical: one wants to be sure it is a proper stream before being too far in an application. The sequence is buffered by the ObjectOutputStream at construction time so that it is pushed on the stream at the first write. This method often leads to complexities in buffered situations or transferring via pipes or sockets. Fortunately, there is a just as simple as an effective solution to all these problems:
Flush the ObjectOutputStream immediately after construction!
ObjectOutputStream myStream = new ObjectOutputStream ( anotherStream );
myStream.flush();
In your case, you will have to use a ObjectOutputStream if you want to read from an ObjectInputStream
The stream protocol includes a stream header, which ObjectInputStream reads in the constructor. You have to defer creating the stream until you have received something:
sock.receive(packetIn);
try {
in = new ObjectInputStream(bIn);
Object o = in.readObject();
} catch (IOException e1) {
e1.printStackTrace();
}
Related
below code to write my objects and byte[] into file with sigBytes being my byte[]
ObjectOutputStream outputOS = new ObjectOutputStream(new FileOutputStream(outputFile));
outputOS.writeInt(sigBytes.length);
outputOS.write(sigBytes);
outputOS.writeObject(text);
outputOS.close();
then when i execute code below i get an java.io.OptionalDataException
ObjectInputStream inputIS = new ObjectInputStream(new FileInputStream(INPUT));
int length = inputIS.readInt();
byte[] sigBytes = new byte[length];
inputIS.read(sigBytes, 0, length);
String text = (String) inputIS.readObject();
Below the error I get at String text = (String) inputIS.readObject():
java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at encryption3.Encryption3.decrypt(Encryption3.java:34)
at encryption3.Encryption3.main(Encryption3.java:53)
EDIT
i can't make the error repeat in a minimal as below??? and i'm really to tired for this..
public static void doThings() {
try {
File file = new File("C:/edges/input.ext");
String text = "Hello";
file.createNewFile();
byte[] sigBytes = (text).getBytes();
ObjectOutputStream outputOS = new ObjectOutputStream(new FileOutputStream(file));
outputOS.writeInt(sigBytes.length);
outputOS.write(sigBytes);
outputOS.writeObject(text);
ObjectInputStream inputIS = new ObjectInputStream(new FileInputStream(file));
int length = inputIS.readInt();
byte[] sigBytes2 = new byte[length];
inputIS.read(sigBytes2, 0, length);
String text2 = (String) inputIS.readObject();
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(EncryptionError.class.getName()).log(Level.SEVERE, null, ex);
}
}
I believe I understand what may be going wrong here... you're currently using read(sigBytes) which does not guarantee that it will read all the data you've requested. In general, InputStream.read(byte[]) and InputStream.read(byte[], int, int) only guarantee that they will read some data before returning, unless the stream is closed. It's entirely possible for them to read less data than is asked for - this often happens if you're reading data over a network, for example, where the stream can return the data it has already received, but won't block forever waiting for more data to come.
If only part of your data is read, then the subsequent readObject call will be reading from some arbitrary point within your original data, which could easily cause an exception to be thrown as it's unlikely to be the start of a valid object representation.
In this case, I believe you want:
inputIS.readFully(sigBytes);
where readFully is guaranteed to fill the byte array, or will throw an exception if it reaches the end of the stream before completing.
From javadocs
Exception indicating the failure of an object read operation due to unread primitive data, or the end of data belonging to a serialized object in the stream. This exception may be thrown in two cases:
An attempt was made to read an object when the next element in the stream is primitive data. In this case, the OptionalDataException's length field is set to the number of bytes of primitive data immediately readable from the stream, and the eof field is set to false.
An attempt was made to read past the end of data consumable by a class-defined readObject or readExternal method. In this case, the OptionalDataException's eof field is set to true, and the length field is set to 0.
EDIT: Your code is running fine in my computer too.
From your code,
You are already writing text as String object to the file with this statement:
outputOS.writeObject(text);
Below statements may not be needed to write a String by converting it into byte[] and write byte[] length + byte array.
outputOS.writeInt(sigBytes.length);
outputOS.write(sigBytes);
I'm a bit confused. I got this block of code :
public void serializeStock(){
FTPClient client = new FTPClient();
try{
client.connect("ftp.**.***");
client.login("***", "*****");
FileInputStream fin = new FileInputStream(someVariableContainingObject); // <-- The object ( StockVault stocks = new StockVault();
ObjectInputStream oos = new ObjectInputStream(fin);
client.storeFile("theObject", oos);
System.out.println("Wrote Stocks data to file");
client.logout();
client.disconnect();
}catch(Exception ex){
ex.printStackTrace();
}
}
I open a connection to my remote FTP server, I now want to write a object named "stocks" to the server. I know I can save the object file first, and then upload it. But is it possible to store the object in a "file" variable or something, and feed it directly to the FileInputStream? This way I wont have to save the object to an actual system file, and then upload it. But make some kind of variable to hold the file, and then upload the "file-variable" to the ftp-server.
It is possible to stream directly to the FTP server, but FileInputStream is not the right class to do so -- it always reads from a local file.
The simplest way to do this in your case may be to use
client.storeFileStream(remoteName)
This method returns an output stream you can write to (instead of sucking up all the data from a given input stream), which seems to be a more natural fit for your case.
Example:
OutputStream os = client.storeFileStream("theObject");
ObjectOutputStream oos = new ObjectOutputStream(os);
// write your object to oos here,
// then close everything.
An alternative that uses the same client method as in your example but no file would be to first write the object to a ByteArrayOutputStream, then create a ByteArrayInputStream from getBytes(), and hand that over to the ftp client.
BTW: The Object stream in your code can be omitted -- you can use the file stream directly:
FileInputStream fin = new FileInputStream(someVariableContainingObject);
client.storeFile("theObject", fin);
// ...
I put a number of objects into the stream, then get byte array out of it and then read everything back. First two pieces of data arrive in good condition, then I get zeroes and then EOF exception. Why?
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject("abcdef");
objectOutputStream.writeInt(1);
objectOutputStream.writeObject(new byte[]{1,2,3,4,5,6,7,8});
objectOutputStream.writeInt(2);
objectOutputStream.writeObject(new byte[]{11,12,13,14,15,16,17,18});
objectOutputStream.close();
byte[] original = byteArrayOutputStream.toByteArray();
System.out.println(Arrays.toString(original));
byte[] b=new byte[8];
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(original));
String s= (String) objectInputStream.readObject(); // works fine
objectInputStream.readInt(); // works fine
objectInputStream.read(b); // why it reads zeroes instead of [1,2,3,4,5,6,7,8]?
System.out.println(Arrays.toString(b));
int length = objectInputStream.readInt(); // EOF unexpectedly reached, why?
objectInputStream.read(b);
}
catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Exception:
java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:375)
at java.io.ObjectInputStream$BlockDataInputStream.readInt(ObjectInputStream.java:2775)
at java.io.ObjectInputStream.readInt(ObjectInputStream.java:949)
I suspect that the first issue is that you need to close() your objectOutputStream. See the ObjectOutputStream documentation for examples.
As well as closing your buffered stream...
You want to have readInt() for each writeInt() (as you are doing) You also need to have readObject() for each writeObject().
If you don't read the same way your wrote, you can't expect it to make any sense.
You are doing
objectOutputStream.writeObject(new byte[]{1,2,3,4,5,6,7,8});
so you need to do
byte[] bytes = (byte[]) objectInputStream.readObject();
Have a look at how ObjectOutputStream handles arrays in writeObject (specifically, look at ObjectOutputStream.writeArray(). It writes an array marker byte (to know what kind of object is stored), then the array length and then the array elements themselves.
Long story short, you should read it back with readObject, not with plain read (unless you want to actually parse that stream of bytes yourself, not expecting your bytes to be retrieved as in the original byte array).
InputStream.read(byte[]) simply gets the raw stream of bytes and writes them in your buffer.
Moreover, the subsequent calls (other than mere read()s) are expected to fail because the pointer is not placed at the beginning of a data structure which the deserializer can understand.
Im working on a Client/server chat application which allows user to send files (images / videos...) through a socket connection.
In order to manage all kind of communication, I use an Object "Packet" which stores all information that I want to send. (Sender, receivers, file ...).
Here is a code sample where I write in the stream :
private void write(Packet packet) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(packet);
this.outStream.write(bos.toByteArray());
}
And outStream is an OutputStream.
Here is my Connection run :
public void run() {
while (isRunning()) {
try {
byte[] buffer = new byte[65536];
// Read from the InputStream
inStream.read(buffer);
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer));
Packet p = (Packet) in.readObject();
} catch (IOException e) {
e.printStackTrace();
this.disconnect();
}
}
}
It works very well for all purpose except files transfer !
I put the file in a byte[] (with filestream) and store the array in my Packet Object.
When the server receive the communication it breaks on the "in.readObject()" and give me a pretty "java io streamcorruptedexception wrong format : 0" exception.
I tried the transfer with a custom byte[] (filled by a string.getBytes()) and it worked very well.
So, what am I doing wrong ?
You're reading from the InputStream to a byte array (with an arbitrary size which could be too small). Then you construct an ObjectInputStream to read from this byte array. Why don't you read your object directly from the InputStream?
ObjectInputStream in = new ObjectInputStream(inStream);
Packet p = (Packet) in.readObject();
No need for a buffer.
Moreover, InputStream.read() doesn't read everything from the InputStream. It reads what is available, and returns the number of bytes read. If you don't loop until it returns -1, you only read a part of what has been sent on the other side.
BTW, you're doing the same mistake on the sending side. Instead of writing your object directly to the output stream, you write it to a byte array, adn then send this byte array. Write your object directly to the stream:
ObjectOutputStream os = new ObjectOutputStream(this.outputStream);
os.writeObject(packet);
No need for a buffer.
hello i have a basic client-server system running using java sockets.
my problem is, that an object that i send from the client to the server does not contain the correct data after it has been sent once.
the first time i send it, it arrives with the correct values, but when i send it another time with different values, it still arrives at the server with the same values as the first time. it also happens if i send a completely different instance of that class. it always arrives with the data, which have been sent the very first time.
when i try this with other objects like java.lang.String it seems to work.
the problematic class looks like this:
public class Vector3f implements Serializable {
private static final long serialVersionUID = 2838034155614698213L;
public float x, y, z;
}
i use objectinputstream and objectoutputstream on both the server and the client to send and receive objects.
let me know, if you need any more information about the system.
thanks!
My guess is that you're changing the values of the fields and then retransmitting the same object. The ObjectOutputStream will notice that it's already sent the original object, and just send a reference the second time.
You could avoid this by calling reset() on the ObjectOutputStream - but I'd be tempted to just use separate instances anyway, possibly even making the class immutable. (Public mutable fields are almost never a good idea.)
The best way in case of serialization you should convert the object into a byte array object and then write into the socket.
// Serialize to a file
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(object);
out.close();
// Serialize to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
out = new ObjectOutputStream(bos) ;
out.writeObject(object);
out.close();
// Get the bytes of the serialized object
byte[] buf = bos.toByteArray();
// Deserialize from a file
File file = new File("filename.ser");
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
// Deserialize the object
Object obj = (Object) in.readObject();
in.close();
// Get some byte array data
byte[] bytes = getBytesFromFile(file);
// see Reading a File into a Byte Array for the implementation of this method
// Deserialize from a byte array
in = new ObjectInputStream(new ByteArrayInputStream(bytes));
in.close();