ข้อมูลการทำให้เป็นอนุกรมเสียหายบนพีซี แต่ไม่ใช่บนอุปกรณ์ Android

ฉันกำลังพัฒนาแอปข้ามแพลตฟอร์มที่ทำงานทั้งบนพีซีและ Android แอปนี้ทำให้ออบเจ็กต์เป็นอนุกรมและบันทึกลงในไฟล์บนเซิร์ฟเวอร์ของเรา ปัญหาที่ฉันพบคือเมื่อฉันดีซีเรียลไลซ์ออบเจ็กต์ใดวัตถุหนึ่งบนพีซี ฉันได้รับข้อผิดพลาดต่อไปนี้:

java.io.StreamCorruptedException: invalid type code: 71
at java.io.ObjectInputStream.readString(ObjectInputStream.java:1646)
at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1736)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1706)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1344)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)

อย่างไรก็ตาม ฉันสามารถดีซีเรียลไลซ์วัตถุบนโทรศัพท์ Android (Samsung s5) ได้สำเร็จ สิ่งนี้ทำให้ฉันงุนงงอย่างสมบูรณ์ ฉันได้จำกัดปัญหาให้แคบลงจนถึงปัญหาแพลตฟอร์ม เนื่องจากฉันได้นำสตริงที่เข้ารหัสโดยตรงและถอดรหัสบนอุปกรณ์ทั้งสองเครื่อง ซึ่งมีข้อผิดพลาดปรากฏขึ้นบนพีซี ไม่ใช่บนอุปกรณ์ Android สิ่งนี้บอกฉันว่าสตริงที่เข้ารหัสไม่ได้เสียหายจริงๆ ฉันพลาดอะไรไปรึเปล่า? ข้อเสนอแนะใด ๆ ที่จะได้รับการชื่นชม

นี่คือรหัสที่ฉันใช้เพื่อทำให้วัตถุเป็นอนุกรม:

public static String objectToString(Serializable object) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        ObjectOutputStream obj = new ObjectOutputStream(out);
        obj.writeObject(object);
        byte[] data = out.toByteArray();
        obj.close();
        out.close();

        return new String(Base64Coder.encode(data));
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

public static Object stringToObject(String encodedObject) {
    try {
        ByteArrayInputStream bin = new ByteArrayInputStream(Base64Coder.decode(encodedObject));
        ObjectInputStream input = new ObjectInputStream(bin);
        try{
        return input.readObject();
        }finally{
            Gdx.app.log(TAG, "Input closed!");
            input.close();
            bin.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

นอกจากนี้ นี่คือตัวเข้ารหัส Base64 I ใช้.


person eBehbahani    schedule 28.04.2014    source แหล่งที่มา
comment
Dalvik ยังคงอาจไม่สามารถสตรีมได้กับ PC JRE จากคำถามนั้น ทำไมไม่ใช้ JSON (หรือ XML)   -  person Elliott Frisch    schedule 28.04.2014
comment
ฉันใช้การเข้ารหัส base64 มาระยะหนึ่งแล้วและไม่มีปัญหาใดๆ ฉันสามารถลองเปลี่ยนวิธีการทำให้เป็นอนุกรมได้ แต่ต้องการหลีกเลี่ยงหากเป็นไปได้   -  person eBehbahani    schedule 28.04.2014


คำตอบ (2)


คุณลืมแปลงสตริงเป็นไบต์[] เพื่อย้อนกลับการแปลงไบต์โดยนัย[] เป็นสตริงที่เกิดขึ้นเมื่อดำเนินการ new String(Base64Coder.encode(data))

ลองสิ่งนี้แทน:

public static Object stringToObject(String encodedObject) {
    try {
        byte[] byteArray = encodedObject.getBytes();
        ByteArrayInputStream bin = new ByteArrayInputStream(Base64Coder.decode(byteArray));

แทน:

public static Object stringToObject(String encodedObject) {
    try {
        ByteArrayInputStream bin = new ByteArrayInputStream(Base64Coder.decode(encodedObject));
person Emanuel Moecklin    schedule 28.04.2014
comment
วิธีการถอดรหัสจะแปลงสตริงเป็นอาร์เรย์ถ่าน (ดูที่นี่: source- code.biz/base64coder/java/Base64Coder.java.txt) นั่นเพียงพอแล้วเหรอ? - person eBehbahani; 28.04.2014
comment
คุณพูดถูก ฉันสมมติว่า Base64Coder.encode จะส่งคืน byte[] แต่จะส่งคืน char[] ดังนั้นสิ่งที่ฉันแนะนำจึงไม่จำเป็นอย่างแน่นอน ฉันจะตรวจสอบว่า Base64Coder.decode(encodedObject) เหมือนกันบน Android และพีซีหรือไม่ ถ้ามันเหมือนกัน แสดงว่า Elliott Frisch น่าจะถูกต้อง หากไม่เหมือนกัน แสดงว่า Base64 lib มีข้อบกพร่องบางประการ และฉันจะลองเปลี่ยนไปใช้เช่น Apache หนึ่ง (commons.apache.org/proper/commons-codec) - person Emanuel Moecklin; 28.04.2014
comment
ความเป็นไปได้อีกอย่างหนึ่งก็คือ encodedObject ไม่เหมือนกัน ซึ่งหมายความว่าการโหลดออบเจ็กต์จากเซิร์ฟเวอร์มีข้อผิดพลาดอยู่แล้ว หากทั้ง encodedObject และสตริง 64 ฐานที่ถอดรหัสไม่แตกต่างกัน และคุณต้องการยึดติดกับการทำให้เป็นอนุกรมของ Java อย่างแน่นอน คุณสามารถทำให้วัตถุเป็นอนุกรม/ดีซีเรียลไลซ์ด้วยตนเองได้ (โดยใช้วิธี readObject/writeObject) - person Emanuel Moecklin; 28.04.2014
comment
ออบเจ็กต์ที่เข้ารหัสจะแตกต่างกันบนพีซีและบน Android แม้ว่าออบเจ็กต์จะเหมือนกันก็ตาม - person eBehbahani; 28.04.2014
comment
วัตถุที่เข้ารหัส = encodedObject (พารามิเตอร์ใน stringToObject)? - person Emanuel Moecklin; 28.04.2014
comment
ใช่ พารามิเตอร์ encodedObject ต่างกันทั้งคู่ - person eBehbahani; 29.04.2014
comment
นั่นหมายความว่าการดาวน์โหลดอ็อบเจ็กต์ซีเรียลไลซ์มีปัญหาอยู่แล้ว และคุณควรตรวจสอบสิ่งนั้นก่อน - person Emanuel Moecklin; 29.04.2014

ปัญหาคือว่า Android เวอร์ชันสูงสุด 7.0 (API 24) ใช้การใช้งาน Apache Harmony Java ซึ่งรูปแบบการทำให้เป็นอนุกรมของวัตถุเข้ากันไม่ได้กับ JRE "ปกติ"

เนื่องจาก Android 7.0 ใช้ OpenJDK และเข้ากันได้

ดูสิ่งนี้ด้วย:

person Ilya Shinkarenko    schedule 16.06.2017