如何序列化对象并将其保存到 Android 中的文件中?

Posted

技术标签:

【中文标题】如何序列化对象并将其保存到 Android 中的文件中?【英文标题】:How do I serialize an object and save it to a file in Android? 【发布时间】:2011-05-06 08:20:38 【问题描述】:

假设我有一些简单的类,一旦它被实例化为一个对象,我希望能够将其内容序列化到一个文件中,并通过稍后加载该文件来检索它......我不知道在哪里从这里开始,我需要做什么才能将此对象序列化为文件?

public class SimpleClass 
   public string name;
   public int id;
   public void save() 
       /* wtf do I do here? */
   
   public static SimpleClass load(String file) 
       /* what about here? */
   

这可能是世界上最简单的问题,因为在 .NET 中这是一个非常简单的任务,但在 android 中我还很新,所以我完全迷路了。

【问题讨论】:

【参考方案1】:

保存(无异常处理代码):

FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();
fos.close();

正在加载(无异常处理代码):

FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
SimpleClass simpleClass = (SimpleClass) is.readObject();
is.close();
fis.close();

【讨论】:

非常有用。您能否解释一下我们是否必须将类序列化为目标文件。 如果您使用 Serializable 接口,此功能会隐式添加到您的类中。如果你想要的只是简单的对象序列化,那就是我会使用的。它也非常容易实现。 developer.android.com/reference/java/io/Serializable.html +1,要保存多个对象,需要技巧:***.com/a/1195078/1321401 是否也应该调用 fos.close() 和 fis.close() ? 我推荐Paper。它使用 Kryo 序列化,比普通的 Java 序列化要快得多。【参考方案2】:

我已经尝试了这 2 个选项(读/写),使用普通对象、对象数组(150 个对象)、地图:

选项1:

FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();

选项2:

SharedPreferences mPrefs=app.getSharedPreferences(app.getApplicationInfo().name, Context.MODE_PRIVATE);
SharedPreferences.Editor ed=mPrefs.edit();
Gson gson = new Gson(); 
ed.putString("myObjectKey", gson.toJson(objectToSave));
ed.commit();

选项 2 比选项 1 快两倍

选项2的不便之处在于您必须编写特定的代码才能读取:

Gson gson = new Gson();
JsonParser parser=new JsonParser();
//object arr example
JsonArray arr=parser.parse(mPrefs.getString("myArrKey", null)).getAsJsonArray();
events=new Event[arr.size()];
int i=0;
for (JsonElement jsonElement : arr)
    events[i++]=gson.fromJson(jsonElement, Event.class);
//Object example
pagination=gson.fromJson(parser.parse(jsonPagination).getAsJsonObject(), Pagination.class);

【讨论】:

为什么说选项 2 更快?也许是因为 SharedPreferences 保存在内存中,而您测量的时间不包括将其保存到文件系统?我问这个是因为我想序列化到对象流必须比 JSON 字符串更有效。 我也不知道为什么,但是官方序列化kotlin文档中似乎也使用了Json。为什么 JSON 是默认的...【参考方案3】:

我刚刚创建了一个类来处理泛型,因此它可以用于所有可序列化的对象类型:

public class SerializableManager 

    /**
     * Saves a serializable object.
     *
     * @param context The application context.
     * @param objectToSave The object to save.
     * @param fileName The name of the file.
     * @param <T> The type of the object.
     */

    public static <T extends Serializable> void saveSerializable(Context context, T objectToSave, String fileName) 
        try 
            FileOutputStream fileOutputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

            objectOutputStream.writeObject(objectToSave);

            objectOutputStream.close();
            fileOutputStream.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

    /**
     * Loads a serializable object.
     *
     * @param context The application context.
     * @param fileName The filename.
     * @param <T> The object type.
     *
     * @return the serializable object.
     */

    public static<T extends Serializable> T readSerializable(Context context, String fileName) 
        T objectToReturn = null;

        try 
            FileInputStream fileInputStream = context.openFileInput(fileName);
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            objectToReturn = (T) objectInputStream.readObject();

            objectInputStream.close();
            fileInputStream.close();
         catch (IOException | ClassNotFoundException e) 
            e.printStackTrace();
        

        return objectToReturn;
    

    /**
     * Removes a specified file.
     *
     * @param context The application context.
     * @param filename The name of the file.
     */

    public static void removeSerializable(Context context, String filename) 
        context.deleteFile(filename);
    


【讨论】:

【参考方案4】:

带有错误处理和添加的文件流关闭的完整代码。将它添加到您希望能够序列化和反序列化的类中。在我的例子中,类名是CreateResumeForm。您应该将其更改为您自己的类名。 Android interface Serializable 不足以将您的对象保存到文件中,它只会创建流。

// Constant with a file name
public static String fileName = "createResumeForm.ser";

// Serializes an object and saves it to a file
public void saveToFile(Context context) 
    try 
        FileOutputStream fileOutputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(this);
        objectOutputStream.close();
        fileOutputStream.close();
     catch (IOException e) 
        e.printStackTrace();
    



// Creates an object by reading it from a file
public static CreateResumeForm readFromFile(Context context) 
    CreateResumeForm createResumeForm = null;
    try 
        FileInputStream fileInputStream = context.openFileInput(fileName);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        createResumeForm = (CreateResumeForm) objectInputStream.readObject();
        objectInputStream.close();
        fileInputStream.close();
     catch (IOException e) 
        e.printStackTrace();
    
    catch (ClassNotFoundException e) 
        e.printStackTrace();
    
    return createResumeForm;

在你的Activity 中这样使用它:

form = CreateResumeForm.readFromFile(this);

【讨论】:

【参考方案5】:

我使用 SharePrefrences:

package myapps.serializedemo;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity 
@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

//Create the SharedPreferences
    SharedPreferences sharedPreferences = this.getSharedPreferences("myapps.serilizerdemo", Context.MODE_PRIVATE);
    ArrayList<String> friends = new ArrayList<>();
    friends.add("Jack");
    friends.add("Joe");
    try 

 //Write / Serialize
 sharedPreferences.edit().putString("friends",
    ObjectSerializer.serialize(friends)).apply();
     catch (IOException e) 
        e.printStackTrace();
    
//READ BACK
    ArrayList<String> newFriends = new ArrayList<>();
    try 
        newFriends = (ArrayList<String>) ObjectSerializer.deserialize(
                sharedPreferences.getString("friends", ObjectSerializer.serialize(new ArrayList<String>())));
     catch (IOException e) 
        e.printStackTrace();
    
    Log.i("***NewFriends", newFriends.toString());


【讨论】:

【参考方案6】:

您必须在您的程序中添加一个 ObjectSerialization 类,以下可能会起作用

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;

    public class ObjectSerializer 

public static String serialize(Serializable obj) throws IOException 
    if (obj == null) return "";
    try 
        ByteArrayOutputStream serialObj = new ByteArrayOutputStream();
        ObjectOutputStream objStream = new ObjectOutputStream(serialObj);
        objStream.writeObject(obj);
        objStream.close();
        return encodeBytes(serialObj.toByteArray());
     catch (Exception e) 
        throw new RuntimeException(e);
    


public static Object deserialize(String str) throws IOException 
    if (str == null || str.length() == 0) return null;
    try 
        ByteArrayInputStream serialObj = new ByteArrayInputStream(decodeBytes(str));
        ObjectInputStream objStream = new ObjectInputStream(serialObj);
        return objStream.readObject();
     catch (Exception e) 
        throw new RuntimeException(e);
    


public static String encodeBytes(byte[] bytes) 
    StringBuffer strBuf = new StringBuffer();

    for (int i = 0; i < bytes.length; i++) 
        strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
        strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
    

    return strBuf.toString();


public static byte[] decodeBytes(String str) 
    byte[] bytes = new byte[str.length() / 2];
    for (int i = 0; i < str.length(); i+=2) 
        char c = str.charAt(i);
        bytes[i/2] = (byte) ((c - 'a') << 4);
        c = str.charAt(i+1);
        bytes[i/2] += (c - 'a');
    
    return bytes;

如果您使用 SharedPreferences 存储数组而不是使用以下内容:-

SharedPreferences sharedPreferences = this.getSharedPreferences(getPackageName(),MODE_PRIVATE);

序列化:-

sharedPreferences.putString("name",ObjectSerializer.serialize(array));

反序列化:-

newarray = (CAST_IT_TO_PROPER_TYPE) ObjectSerializer.deSerialize(sharedPreferences.getString(name),null);

【讨论】:

以上是关于如何序列化对象并将其保存到 Android 中的文件中?的主要内容,如果未能解决你的问题,请参考以下文章

如何拆分/解析 JSON 数据并将其保存到 SQL 服务器中?

如何保存从Kinect 2.0收集的Body数据并将其保存在JSON文件中?

自定义对象的 Android ArrayList - 保存到 SharedPreferences - 可序列化?

如何从服务器下载文件并将其保存在 Android SD 卡中的特定文件夹中?

解析嵌套的 JSON 并将其保存到 SQLite 中,然后检索它

在 ImageView 中显示图像并将其保存到 Android 上的内部存储中