Java ObjectInputStream генерирует EOFException с большим объектом
У меня есть этот метод для десериализации:
public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
Object res = is.readObject();
is.close();
in.close();
return res;
}
и этот для сериализации:
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
byte[] res = out.toByteArray();
out.close();
os.close();
return res;
}
Я использую эти методы для сериализации и десериализации объекта класса, который имеет только строку и arrayList другого класса, обмениваемого между двумя устройствами. И класс объекта, и класс arrayList реализуют сериализуемый.
Когда я отправляю объект, содержащий до 3 элементов в arrayList, эти методы работают отлично. Однако, когда arrayList имеет 4 или более элементов, устройство, получающее объект, все еще обнаруживает, что некоторые данные "прибыли", но метод десериализации генерирует "EOFException" в "Object res = is.readObject();" линия.
Есть идеи о том, в чем проблема?
РЕДАКТИРОВАТЬ
Это класс arrayList:
import java.io.Serializable;
public class Info implements Serializable {
public Info() {
...
}
...
}
Это класс объекта:
import java.io.Serializable;
import java.util.ArrayList;
public class BluetoothDataContainer implements Serializable{
private ArrayList<Info> dataList;
private String originDevice;
public BluetoothDataContainer(String originDevice){
dataList= new ArrayList<Info>();
this.originDevice = originDevice;
}
...
}
Это код, который я использую для отправки объекта:
BluetoothDataContainer data = new BluetoothDataContainer(mBluetoothAdapter.getName());
...
// add needed info to variable 'data'
...
s.write(data);
Где s - это поток с методом write:
private BluetoothSocket mmSocket = bluetoothDevice.createRfcommSocketToServiceRecord(ID_CONNECTION);
private OutputStream mmOutStream = mmSocket.getOutputStream();
...
public void write(BluetoothDataContainer m) {
try {
mmOutStream.write(serialize(m));
} catch (IOException e) {
this.mContext.showToast("IOException caught in thread ConnectedThread [Bluetooth connection handler] - write() !");
}
//cancel();
this.interrupt();
}
И вот как я обрабатываю объект, когда он читается:
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
final BluetoothDataContainer data;
try {
data = (BluetoothDataContainer) deserialize(readBuf);
...
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
И вот как я читаю объект:
private final Handler mHandler; // value set in the constructor
...
public void run() {
mmInStream = bluetoothSocket.getInputStream();
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes;
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
this.mContext.showToast("ConnectedThread [Bluetooth connection handler] data received !");
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(1, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
this.mContext.showToast("IOException caught in thread ConnectedThread [Bluetooth connection handler] - run() !");
}
}
1 ответ
Очевидно, что вы не "обменялись" всем байтовым массивом в случае сбоя.
bytes = mmInStream.read(buffer);
Вы не можете знать только из этого, читали ли вы:
- целое сообщение
- менее одного сообщения
- более одного сообщения.
Поскольку у вас уже есть сокет с входным и выходным потоками, меня не удивляет, почему вы вообще создаете байтовые массивы. Просто заверните ObjectOutputStream
вокруг выходного потока сокета и использовать writeObject()
, На приемнике заверните ObjectInputStream
вокруг сокета входного потока и использования readObject()
,
Обратите внимание, что вы должны использовать одни и те же потоки объектов в течение всего срока службы сокета, и если вы отправляете объекты в обоих направлениях, вы должны создать поток вывода объекта перед потоком ввода объекта для одного и того же сокета: в противном случае вы можете получить взаимоблокировку.