객체를 직렬화하여 Android의 파일로 저장하려면 어떻게합니까?


128

간단한 클래스가 있고 객체로 인스턴스화되면 내용을 파일로 직렬화하고 나중에 해당 파일을로드하여 검색 할 수 있기를 원한다고 가정 해보십시오. 여기서 어디서부터 시작 해야할지 모르겠습니다. 이 객체를 파일로 직렬화하려면 어떻게해야합니까?

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에서는 완전히 새롭기 때문에 완전히 길을 잃었습니다.

답변:


250

저장 (예외 처리 코드 없음) :

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

굉장히 유용하다. 객체 파일로 쓰기 위해 클래스를 직렬화해야하는지 설명해 주시겠습니까?
Arun Chettoor

4
Serializable 인터페이스를 사용하면이 기능이 클래스에 암시 적으로 추가됩니다. 당신이 원하는 모든 것이 간단한 객체 직렬화라면, 그것이 내가 사용하는 것입니다. 구현하기가 매우 쉽습니다. developer.android.com/reference/java/io/Serializable.html
mtmurdock 22

6
+1, 여러 객체를 저장하려면 트릭이 필요합니다. stackoverflow.com/a/1195078/1321401
Luten

2
fos.close () 및 fis.close ()도 호출해야합니까?
IcedDante

Paper를 추천 합니다. Kryo 직렬화를 사용하며 일반적인 Java 직렬화보다 훨씬 빠릅니다.
알렉세이 마시

36

일반 객체, 객체 배열 (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);

3
왜 옵션 2가 더 빠르다고 말할까요? 아마도 SharedPreferences가 메모리에 유지되고 측정 시간에 파일 시스템에 저장하지 않았기 때문일까요? 객체 스트림으로 직렬화하는 것이 JSON 문자열보다 효율적이어야한다고 생각하기 때문에 이것을 묻습니다.
CesarPim

10

방금 Generics로 이것을 처리하는 클래스를 만들었으므로 직렬화 가능한 모든 객체 유형과 함께 사용할 수 있습니다.

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

}

7

오류 처리 및 추가 된 파일 스트림이있는 완전한 코드가 닫힙니다. 직렬화 및 역 직렬화 할 수 있도록 클래스에 추가하십시오. 제 경우에는 클래스 이름이 CreateResumeForm입니다. 자신의 클래스 이름으로 변경해야합니다. Android인터페이스 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);

0

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

0

프로그램에 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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.