0

我想写然后从文件中读取一个对象。下面我附上代码示例向您展示我的想法(这只是示例,我的对象更复杂,但问题是一样的)。

我的问题是:

  1. 如果我不将 TestObject 字段设为静态,则 testObject.points 在 readObject 方法开始时变为 null。我不明白为什么。谁能给我很好的解释?

  2. 我想写一个对象,然后再写 2 个对象,然后将它们全部读取(多个对象写入/读取 - 我想为 Android 创建日志文件)。

你可以帮帮我吗?

// ... 进口

public class TestObject implements Serializable{

    transient public ArrayList<Point[]> points;

    public TestObject()
    {
        points = new ArrayList<Point[]>();
        Point[] p1 = new Point[1];
        p1[0] = new Point(1,1);
        Point[] p2 = new Point[2];
        p2[0] = new Point(2,2);
        p2[1] = new Point(2,2);
        points.add(p1);
        points.add(p2);
    }

    private void writeObject(ObjectOutputStream stream) throws IOException 
    {
        stream.defaultWriteObject();
        stream.writeInt(points.size());
        Point[] pointsArray = null;
        for (int i = 0; i < points.size(); i++)
        {
            pointsArray = ((Point[])points.get(i));
            stream.writeInt(pointsArray.length);
            for (int j = 0; j < pointsArray.length; j++)
            {
                stream.writeInt(pointsArray[j].x);
                stream.writeInt(pointsArray[j].y);
            }
        }
    }

    private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException
    {
        stream.defaultReadObject();
        points = new ArrayList<Point[]>();
        int pointsSize = stream.readInt();
        for (int i = 0; i < pointsSize; i++)
        {
            int arraySize = stream.readInt();
            Point[] pointsArray = new Point[arraySize];
            for (int j = 0; j < arraySize; j++)
            {   
                pointsArray[j] = new Point(stream.readInt(), stream.readInt());
            }
            points.add(pointsArray);
        }
    }

    public void writeLog()
    {
        File file = new File ("C:\\!\\", "data.log");
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(file, true);
            //fos = openFileOutput(Environment.getExternalStorageDirectory().getAbsolutePath() + "/data.log", Context.MODE_APPEND);
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(this);
            os.close(); 
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public TestObject readLog()
    {
        TestObject testObject = new TestObject();
        testObject.points = new ArrayList<Point[]>();
        try{
            File file = new File ("C:\\!\\", "data.log");
            FileInputStream fis  = new FileInputStream(file);
            ObjectInputStream reader = new ObjectInputStream(fis);  
            testObject = (TestObject) reader.readObject();
            reader.close();
        } catch (Exception e) {
         //TODO Auto-generated catch block
         e.printStackTrace();
        }

        return testObject;
    }
}

还有我的主课

// ... 进口

public class Main {

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

            TestObject testObject = new TestObject();
            testObject.writeLog();
            testObject.readLog();

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

同样,这只是一个例子。真正的应用程序是为Android。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import android.graphics.Point;
import android.os.Environment;

public class LogInfo implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 2281758309050283667L;
    transient public ArrayList<Point[][]> strokes;
    transient public LinkedList<byte[]> codes;

    public LogInfo()
    {
        strokes = new ArrayList<Point[][]>();
        codes = new LinkedList<byte[]>();
    }

    private void writeObject(ObjectOutputStream stream) throws IOException 
    {
        stream.defaultWriteObject();
        stream.writeInt(strokes.size());
        Point[][] pointsArray = null;
        for (int i = 0; i < strokes.size(); i++)
        {
            pointsArray = ((Point[][])strokes.get(i));
            stream.writeInt(pointsArray.length);
            for (int j = 0; j < pointsArray.length; j++)
            {
                stream.writeInt(pointsArray[j].length);
                for (int k = 0; k < pointsArray[j].length; k++)
                {
                    stream.writeInt(pointsArray[j][k].x);
                    stream.writeInt(pointsArray[j][k].y);
                    //stream.writeObject(elementData[i]);
                }
            }
        }

        int size = codes.size();

        stream.writeInt(size);
        for (int i = 0; i < size; i++)
        {
            stream.write(codes.get(i));
        }
    }

    private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException
    {
        strokes = new ArrayList<Point[][]>();
        stream.defaultReadObject();
        int strokesSize = stream.readInt();
        for (int i = 0; i < strokesSize; i++)
        {
            int arrayXSize = stream.readInt();
            Point[][] points = new Point[arrayXSize][];
            for (int j = 0; j < arrayXSize; j++)
            {
                int arrayYSize = stream.readInt();
                points[j] = new Point[arrayYSize];
                for (int k = 0; k < arrayYSize; k++)
                    points[j][k] = new Point(stream.readInt(), stream.readInt());
            }
            strokes.add(points);
        }

        int codesSize = stream.readInt();
        codes = new LinkedList<byte[]>();
        for (int i = 0; i < codesSize; i++)
        {
            byte[] buffer = new byte[3];
            stream.read(buffer, 0, 3);
            codes.add(buffer);
        }
    }

    public void writeLog()
    {
        File file = new File (Environment.getExternalStorageDirectory().getAbsolutePath(), "data.log");
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(file, true);
            //fos = openFileOutput(Environment.getExternalStorageDirectory().getAbsolutePath() + "/data.log", Context.MODE_APPEND);
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(this);
            os.close(); 
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public LogInfo readLog()
    {
        try{
            File file = new File (Environment.getExternalStorageDirectory().getAbsolutePath(), "data.log");
            FileInputStream fis  = new FileInputStream(file);
            ObjectInputStream reader = new ObjectInputStream(fis);  
            reader.readObject();
            reader.close();
        } catch (Exception e) {
         //TODO Auto-generated catch block
         e.printStackTrace();
        }

        return this;
    }
}

我从不同的类调用 writeLog 和 readLog,其中我有一个对象实例。

// WRITE TO FILE
logInfo.writeLog();

// CLEAR LOG VARIABLE (NOT FILE)
delAllLogInfo();

// READ FROM FILE
LogInfo newLogInfo = logInfo.readLog();
4

3 回答 3

1
  1. 如果我不将 TestObject 字段设为静态,则 testObject.points 在 readObject 方法开始时变为 null。我不明白为什么。谁能给我很好的解释?

瞬态字段被反序列化为空。请参阅对象序列化规范。静态字段根本不会反序列化,它们保持当前值。

  1. 我想写一个对象,然后再写 2 个对象,然后将它们全部读取(多个对象写入/读取 - 我想为 Android 创建日志文件)。

如果您始终打开相同的文件,这不是问题。如果不这样做,则需要在第二次和后续时间以附加模式打开文件,并使用ObjectOutputStream不会在第二次和后续时间写入标头的派生类。

于 2013-05-13T03:18:45.170 回答
0

我看到的关键问题是,您在 readLog() 方法的开头创建了一个新的 TestObject 对象(并且此方法可能应该是静态的)并给它一个 ArrayList,然后在方法,您将这个 TestObject 实例替换为另一个完全不同的实例,一个来自文件的反序列​​化,并且似乎期望新的 TestObject 将保留创建并添加到丢弃的 TestObject 的 ArrayList。这行不通。解决方案是反序列化后创建ArrayList ,以便添加到方法实际返回的TestObject中。

考虑改变这个:

public TestObject readLog()
{
    // the two lines below are at best not necessary and at worst are misleading
    // since the deserialized TestObject will over-write anything done here
    TestObject testObject = new TestObject();  
    testObject.points = new ArrayList<Point[]>(); // again this will be discarded

    try{
        File file = new File ("C:\\!\\", "data.log");
        FileInputStream fis  = new FileInputStream(file);
        ObjectInputStream reader = new ObjectInputStream(fis);  
        testObject = (TestObject) reader.readObject();
        reader.close();
    } catch (Exception e) {
     //TODO Auto-generated catch block
     e.printStackTrace();
    }

    return testObject;

对此:

public static TestObject readLog()
{
    TestObject testObject = null;
    ObjectInputStream reader = null;
    try{
        File file = new File ("C:\\!\\", "data.log");
        FileInputStream fis  = new FileInputStream(file);
        reader = new ObjectInputStream(fis);  
        testObject = (TestObject) reader.readObject();

        testObject.points = new ArrayList<Point[]>();  // **** placement is everything

        // reader.close();
    } catch (Exception e) {
     //TODO Auto-generated catch block
     e.printStackTrace();
    } finally {
      if (reader != null) {
        reader.close();
      }
    }

    return testObject;

或者也许更好,更干净,给 TestObject 一个公共方法,比如initPoints()让 TestObject 自己做这件事。

public void initPoints() {
   points = new ArrayList<Point[]>();
}

然后在反序列化对象后调用它:

    testObject = (TestObject) reader.readObject();
    testObject.initPoints(); 

无论你做什么,使点场静态是一个非常非常糟糕的主意。只是不要考虑它。

附录:如果您的目标实际上是保存 Points 数据,那么您最好创建自己的 Point 类并将其用于当前类的包装类中。

于 2013-05-13T00:53:13.770 回答
0

我想我现在明白了。我应该使我的字段不是瞬态的,并且我的读取对象方法应该如下所示: public TestObject readLog()

{
    try{
        File file = new File ("C:\\!\\", "data.log");
        FileInputStream fis  = new FileInputStream(file);
        ObjectInputStream reader = new ObjectInputStream(fis);  
        reader.readObject();
        reader.close();
    } catch (Exception e) {
     //TODO Auto-generated catch block
     e.printStackTrace();
    }

    return this;
}

我对么?这似乎有效

于 2013-05-13T01:35:11.473 回答