유니티에서 데이터 관리하기 (바이너리 저장)

유니티에서 데이터 관리하기

– 바이너리로 저장하고 로드하기

 

unity3d data management

유니티에서 바이너리(Binary)형태로 저장하고, 저장한 데이터를 불러오는 방법에 대해서 살펴보겠습니다.

저장할 클래스는 아래 내용입니다. 변수에 붙는 Attribute들이 XML로 저장하는 방식과 조금 다릅니다.


[Serializable]
public class Person
{
    public int age;
    public string name;

    public override string ToString()
    {
        return "age: " + age + " name: " + name;
    }
}

클래스 위에 [Serializable] Attribute를 붙여줘야 바이너리 형태로 저장이 가능합니다.

이제 저장하는 함수를 살펴보겠습니다.


public void BinarySerialize(Person person, string filePath) 
{ 
    BinaryFormatter formatter = new BinaryFormatter(); 
    FileStream stream = new FileStream(filePath, FileMode.Create); 
    formatter.Serialize(stream, person); 
    stream.Close(); 
}

불러오는 함수 또한 흐름이 같습니다. XML로 저장 / 로드를 했던 분들이라면 크게 어렵지 않게 보일겁니다.

이제 전체 코드를 보겠습니다.

using System;  
using UnityEngine;  
using System.Collections;  
using System.Runtime.Serialization.Formatters.Binary;  
using System.IO;  

public class BinaryFomatterTest : MonoBehaviour  
{  
    [Serializable]  
    public class Person  
    {  
        public int age;  
        public string name;  
          
        public override string ToString()  
        {  
            return "age: " + age + " name: " + name;  
        }  
    }  
      
    string filePath = string.Empty;  
    Person person;  
      
    void Start()  
    {  
        filePath = Application.dataPath + "/test.bin";  
        person = new Person { age = 29, name = "Ronnie" };  
    }  
      
    void OnGUI()  
    {  
        if (GUILayout.Button("Save"))  
        {  
            BinarySerialize(person, filePath);  
        }  
          
        if (GUILayout.Button("Load"))  
        {  
            if (System.IO.File.Exists(filePath))  
            {  
                person = BinaryDeserialize(filePath);  
                Debug.Log(person);  
            }  
        }  
    }  
      
    public void BinarySerialize(Person person, string filePath)  
    {  
        BinaryFormatter formatter = new BinaryFormatter();  
        FileStream stream = new FileStream(filePath, FileMode.Create);  
        formatter.Serialize(stream, person);  
        stream.Close();  
    }  
      
    public Person BinaryDeserialize(string filePath)  
    {  
        BinaryFormatter formatter = new BinaryFormatter();  
        FileStream stream = new FileStream(filePath, FileMode.Open);  
        Person person = (Person)formatter.Deserialize(stream);  
        stream.Close();  
          
        return person;  
    }  
}

실행을 해서 결과를 살펴보겠습니다. 빈 게임 오브젝트를 하나 생성한 후, 위의 스크립트를 컴포넌트로 추가해서 실행합니다.

unity3d data save1

먼저 Save 버튼을 누르면 아래와 같이 test.bin 파일이 생성됩니다.

unity3d data save1

파일이 생성된 것을 확인한 뒤, Load 버튼을 누르면 아래와 같이 콘솔 창에, 위에서 저장했던 클래스 내용이 출력되는 것을 확인할 수 있습니다.

unity3d data save3

차근차근 살펴보면 어렵지 않게 이해하실 수 있습니다. 위에 나온 함수를 잘 응용하셔서 사용하시면 됩니다.

또한 지금의 함수는 Person 타입의 객체만 저장이 가능한데, C#의 Generic을 이용하면 모든 객체를 통째로 저장이 가능합니다.

아래 처럼 수정을 하면 모든 객체를 저장 가능한 형태가 됩니다.

 

저장하는 함수

public void BinarySerialize<T>(T t, string filePath)
{
    BinaryFormatter formatter = new BinaryFormatter();
    FileStream stream = new FileStream(filePath, FileMode.Create);
    formatter.Serialize(stream, t);
    stream.Close();
}

 

불러오는 함수

public T BinaryDeserialize<T>(string filePath)
{
    BinaryFormatter formatter = new BinaryFormatter();
    FileStream stream = new FileStream(filePath, FileMode.Open);
    T t = (T)formatter.Deserialize(stream);
    stream.Close();

    return t;
}

함수명 뒤에 <T> 라고 타입을 지정하고 각 객체 타입 마다 T를 넣어주면 됩니다.

이 함수들을 호출할 때는 아래와 같이 사용하면 됩니다. 호출할 때는 저장할 클래스 타입을 꺽쇠 괄호 안에 명시를 해주면 됩니다.

<Person> 이렇게요.

if (GUILayout.Button("Save"))
{
    BinarySerialize<Person>(person, filePath);
}

if (GUILayout.Button("Load"))
{
    if (System.IO.File.Exists(filePath))
    {
        person = BinaryDeserialize<Person>(filePath);
        Debug.Log(person);
    }
}

Generic은 잘 사용하면 매우 편리한 문법입니다. C++의 템플릿 같은 기능을 합니다. 이 내용이 잘 이해가 되지 않으시는 분들은 Generic에 대한 내용을 검색하셔서 보시면 도움이 많이 되실 겁니다.

그런데 왜 XML로 저장이 가능한데 바이너리로 저장하는 방법을 알아야 할까요? 이 질문에 대한 대답을 두 가지 정도로 요약해서 해보겠습니다.

첫째 XML로 저장하는 방법은 Public으로 선언된 것들만 저장이 가능하다.

-> 클래스도 Public으로 선언이 되어야 하고, 저장할 변수들도 Public으로 선언이 되어야 합니다.

둘째 바이너리 형태로 저장 / 로드하는 방법이 속도면에서 더 빠르고 용량면에서도 이익입니다.

지난 번에 다뤘던 정도의 XML 데이터라면 속도차이가 크게 나지 않지만, 저장 / 로드해야하는 데이터가 큰 경우 속도 차이가 나게 되고, 용량 차이도 더 나게 됩니다.

 

물론 바이너리 파일 안을 살펴보면, 알아볼 수 없는 형태로 되어 있기 때문에 따로 문서를 수정하는 것은 힘듭니다.

외부에서 관리를 해야하는 경우에는, Json / XML 등의 형태가 더 좋을 수도 있습니다.

언제나 만능은 없습니다. 상황에 맞게 사용하시기 바랍니다.

 

내용 끝까지 읽어주셔서 감사합니다.
배너 클릭은 저에게 많은 힘이 됩니다.
감사합니다 🙂

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, C++/C#, 1인 기업에 관심이 많습니다.

2 Responses

  1. 박수환 댓글:

    포스팅 잘봤습니다. 유니티 공부 중인데, 경로를 지정할 때 모바일 같은 경우는 어떻게 지정하는건가요?

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Please turn AdBlock off

Notice for AdBlock users

Please turn AdBlock off