我想编写然后从文件中读取一个Object。下面我附上代码示例以向您展示我的想法(它只是示例,我的对象更复杂,但问题是相同的)。
我的问题是:
如果我不将TestObject字段设置为静态,则testObject.points在readObject方法的启动时变为null。我不明白为什么。有人能给我很好的解释吗?
我想写一个Object,然后另外两个对象,然后读完它们(多个对象写/读 - 我想为Android创建日志文件)。
你能帮帮我吗?
// ... IMPORT
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;
}
}
我的主要班级
// ... IMPORT
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();
答案 0 :(得分:1)
- 如果我不将TestObject字段设置为静态,则testObject.points在readObject方法启动时变为null。我不明白为什么。谁能给我很好的解释呢?
醇>
瞬态字段被反序列化为null。请参阅对象序列化规范。静态字段根本没有反序列化,它们保持当前值。
- 我想写一个Object,然后另外两个对象,然后读完所有(多个对象写/读 - 我想为Android创建日志文件)。
醇>
如果您始终打开同一个文件,则这不是问题。如果您没有,则需要在第二次及以后的时间以附加模式打开文件,并使用ObjectOutputStream
的派生类,该类在第二次及以后的时间内不会写入标题。 / p>
答案 1 :(得分:0)
我看到的关键问题是,你在readLog()方法的开头创建一个新的TestObject对象(这个方法可能应该是静态的)并给它一个ArrayList,但是在mid在方法的主体中,您将这个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类并在当前类的包装类中使用它。
答案 2 :(得分:0)
我想我现在明白了。我应该让我的字段不是瞬态的,我的读取Object方法应如下所示: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;
}
我说错了吗?这似乎有效