将多个对象写入和读取到文件中

4

我正在设计一款针对安卓系统的手写应用。

我希望每当用户按下回车键时,能够将信息(class LogInfo)写入日志文件。

接下来,我想要读取已存储的信息。

这是我的一个类中的自定义写入方法:

public class LogInfo implements Serializable {

private static final long serialVersionUID = -5777674941129067422L;

public static List<Point[][]> strokes;
public static List<byte[]> codes;

// Only write and read methods shown

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));
    }
}

这是read方法:

private void readObject(java.io.ObjectInputStream stream)
    {
        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();
        for (int i = 0; i < codesSize; i++)
        {
            byte[] buffer = new byte[3];
            stream.read(buffer, 0, 3);
            codes.add(buffer);
        }
    }

当我只保存一个对象时,它的工作效果很好。但当我尝试保存多个对象时,读取就出现问题(会抛出StreamCorruptedException异常)。在while循环中,它只读取了一个对象!

在主类中,我只使用了两个简单的方法:

// WRITE TO FILE
logInfo.writeLog();

// READ FROM FILE
ArrayList<LogInfo> logInfoArrayList = logInfo.readLog();

定义为:

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 ArrayList<LogInfo> readLog()
{
    ArrayList<LogInfo> logInfoArray = new ArrayList<LogInfo>();

    try{
        File file = new File (Environment.getExternalStorageDirectory().getAbsolutePath(), "data.log");
        FileInputStream fis  = new FileInputStream(file);
        ObjectInputStream reader = new ObjectInputStream(fis);  

        LogInfo tempLogInfo = new LogInfo();
        while((tempLogInfo = (LogInfo)reader.readObject()) != null)
            logInfoArray.add(tempLogInfo);
        reader.close();
    } catch (Exception e) {
     //TODO Auto-generated catch block
     e.printStackTrace();
    }

    return logInfoArray;
}

更新请求:

//We use this class to not write a header in a file that already exist
class MyObjectOutputStream extends ObjectOutputStream {

    public MyObjectOutputStream(OutputStream os) throws IOException {
        super(os);
      }

    @Override
    protected void writeStreamHeader() {}
}

你能否发布异常堆栈跟踪? - gZerone
05-10 10:56:40.320: W/System.err(26121): java.io.StreamCorruptedException: 格式错误:ac 05-10 10:56:40.335: W/System.err(26121): 在java.io.ObjectInputStream.corruptStream(ObjectInputStream.java:701) 05-10 10:56:40.340: W/System.err(26121): 在java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:814) 05-10 10:56:40.345: W/System.err(26121): 在java.io.ObjectInputStream.readObject(ObjectInputStream.java:2003) 05-10 10:56:40.350: W/System.err(26121): 在com.myapp.LogInfo.readLog(LogInfo.java:116) - Marek
循环直到 null 是不正确的。readObject() 在流结束时不会返回 null,而是会抛出 EOFException 异常。 - user207421
3个回答

5
  1. 如果你没有特殊处理,就不能向使用ObjectOutputStream创建的现有文件附加内容。虽然有关于扩展ObjectOutputStream并重写writeStreamHeader()方法以便第二次不写入流头部的技巧,但我不推荐这样做。你应该重新编写整个文件,也许作为一个列表。

  2. 你不需要所有这些代码,只需使strokescodes非静态和非瞬态,并完全摒弃readObject()writeObject()方法。


点类不可序列化。我无法放弃覆盖readObject()和writeObject()。 - Marek
java.awt.Point是可序列化的。您是否在使用不同的类? - user207421
我正在使用import android.graphics.Point。当我将此字段设置为非静态时,即使使用那些方法,我也会收到一个“Point不可序列化”的异常。为什么呢? - Marek
因为它尝试自动序列化它们。我会将它们设置为非静态和瞬态。 - user207421
因为你从readObject()获取了一个新对象,而不是你设置值的那个对象。 - user207421
显示剩余4条评论

0

@EJP是正确的。不能将内容附加到使用ObjectOutputStream创建的现有文件中。您可以执行以下步骤来解决此问题: 1. 保留ObjectOutputStream对象引用 2. 在调用writeObject()之后,不要调用close() 3. 提供一个关闭ObjectOutputStream的方法。


问题已经使用自定义ObjectOutputStream解决。 - Marek
你是怎么解决这个问题的?你介意分享一下你的自定义ObjectOutputStream代码吗? - handrenliang
你可以在问题中找到最新的代码。你只需要重写writeStreamHeader()方法。 - Marek

0

有一种方法可以将多个对象保存在一个文件中:首先应该创建一个对象数组 (Object[] objects),然后将你的对象逐一作为对象放入此数组中,最后使用writeObject(objects)方法写入此数组。 祝好运。


当您不想同时将所有数据存储在RAM中时,此解决方案存在问题。只有在能够保证数据填充RAM的情况下才能正常工作。 - Dani Feldman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接