ObjectInputStream не имеет доступных байтов после создания с помощью ByteArrayInputStream

Я создаю класс, который обрабатывает двоичную де / сериализацию. Метод open() получает InputStream и OutputStream, Те созданы другим open() метод, который получает путь в качестве аргумента. InputStream на самом деле ByteArrayInputStream, Я уже сделал несколько тестов, чтобы доказать, что InputStream прибывает в open() метод с содержанием - и это на самом деле. Но когда я пытаюсь установить ObjectInputStream используя это, это не работает. Не выдается никаких исключений, но когда я пытаюсь прочитать из него байты, это всегда дает мне -1,

Класс BinaryStrategy

public class BinaryStrategy implements SerializableStrategy{
  public BinaryStrategy(){
    try{
        open("products.ser");
    }catch(IOException ioe){

    }
  } 
  @Override
  public void open(InputStream input, OutputStream output) throws IOException  {
    try{
        this.ois = new ObjectInputStream(input);
    }catch(Exception ioe){
        System.out.println(ioe);
    }
    this.oos = new ObjectOutputStream(output);
  }
  @Override
  public void writeObject(fpt.com.Product obj) throws IOException {
    oos.writeObject(obj);
    oos.flush();
  }
  @Override
  public Product readObject() throws IOException {
    Product read = new Product();
    try{
        read.readExternal(ois);
    }catch(IOException | ClassNotFoundException exc){
        System.out.println(exc);
    }
    return read;
  }
}

интерфейс SerializableStrategy (просто метод по умолчанию)

    default void open(Path path) throws IOException {
    if (path != null) {
        ByteArrayInputStream in = null;
        if (Files.exists(path)) {
            byte[] data = Files.readAllBytes(path);
            in = new ByteArrayInputStream(data);
        }
        OutputStream out = Files.newOutputStream(path);
        open(in, out);
    }

Класс продукта

public class Product implements java.io.Externalizable {
    @Override
public void writeExternal(ObjectOutput out) throws IOException {
    out.writeLong(getId());
    out.writeObject(getName());
    out.writeObject(getPrice());
    out.writeObject(getQuantity());
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    this.setId((Long)in.readLong());
    this.setName((String) in.readObject());
    this.setPrice((Double) in.readObject());
    this.setQuantity((Integer) in.readObject());
}

Я должен был персонализировать это, потому что атрибуты SimplePropertys

В public void open(InputStream input, OutputStream output) Я попытался сделать некоторые вещи, как следует, чтобы проверить:

    public void open(InputStream input, OutputStream output) throws IOException {
    try{
        System.out.println(input.available() + " " + input.read() + " " + input.read());
        //is gives me: 181 172 237
        //181 is the exact size of the file I have, so i think that the Output is ok
        //172 237 - just some chars that are in the file
        //I know that for now on it is going to give me an excepetion because
        // of the position of the index that is reading. I did it just to test
        this.ois = new ObjectInputStream(input);
    }catch(Exception ioe){
        System.out.println(ioe);
    }
    this.oos = new ObjectOutputStream(output);
}

А потом другой тест:

public void open(InputStream input, OutputStream output) throws IOException {
    try{
        this.ois = new ObjectInputStream(input);
        System.out.println(ois.available() + " " + ois.read());
        //here is where I am receiving -1 and 0 available bytes!
        //so something is going wrong right here.
        //i tried to just go on and try to read the object,
        //but I got a EOFException, in other words, -1.
    }catch(Exception ioe){
        System.out.println(ioe);
    }
    this.oos = new ObjectOutputStream(output);
}

3 ответа

Решение

ObjectInputStreamвнутренне использует BlockDataInputStream выполнить свои операции чтения. Это читает блок данных, а не просто байт, как мы ожидаем, когда вы вызываете read, Он читает байт, только если он падает как "блок"

Вывод не то, что я ожидал. Но, если вы посмотрите на код ObjectInputStream.read(), это имеет смысл.

Итак, в вашем случае имеет смысл использовать только readObject восстановить состояние ваших объектов.

Вот ваш код снова...

class SimpleJava {

    public static void open(InputStream input, OutputStream output) throws IOException {

        try {
            ObjectInputStream ois = new ObjectInputStream(input);
            System.out.println(ois.available());// 0
            System.out.println(ois.available() + " " + ois.read() + " " + ois.read());// 0 -1 -1
            // Reads the object even if the available returned 0 
            // and ois.read() returned -1
            System.out.println("object:" + ois.readObject());// object:abcd
        }
        catch (Exception ioe) {
            ioe.printStackTrace();
        }
    }

    static void open(Path path) throws IOException {

        if (path != null) {
            ByteArrayInputStream in = null;
            if (Files.exists(path)) {
                byte[] data = Files.readAllBytes(path);
                in = new ByteArrayInputStream(data);
            }
            OutputStream out = Files.newOutputStream(path);
            open(in, out);
        }
    }

    public static void main(String[] args) throws Exception {

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("/home/pradhan/temp.object")));
        oos.writeObject("abcd");//writes a string object for us to read later
        oos.close();
        //
        open(FileSystems.getDefault().getPath("/home/user/temp.object"));
    }
}

Вот выход...

0
0 -1 -1
object:abcd

Пожалуйста, проверьте, если файл представлен path имеет объект Java, записанный в него.
Из документа API ObjectInputStream https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html

ObjectInputStream десериализует примитивные данные и объекты, ранее написанные с использованием ObjectOutputStream.

ObjectInputStream используется для восстановления этих объектов, ранее сериализованных.

Если вы делаете this.ois.readObject()и вы получаете -1, есть вероятность, что файл не содержит объекта в нем.

Обновить: readObject возвращает объект, а не int, Если вы используете read методы в oisи вы получаете -1, то файл пуст.

Кроме того, есть вероятность, что ваш файл содержит -1 в качестве содержимого;)

Проблема заключалась в том, что я читал ObjectInputStream неправильный путь. Это было как:

read.readExternal(ois);

но правильный путь:

read = (Product)ois.readObject();

И из-за исключений, которые я получал за это, я подумал, что проблема была в строительстве ObjectInputStream когда используешь ByteArrayInputStream, Какая большая ошибка!:D

Спасибо всем, кто пытался помочь.

Другие вопросы по тегам