#31 직렬화

국기웅·2024년 5월 30일
post-thumbnail

직렬화

직렬화는 데이터를 저장하는것과 밀접한 관계가 있다.
보통 데이터를 저장하면, 컴퓨터의 메모리상에 저장된다. 하지만 이런 메모리의 공간은 프로그램을 실행할때마다 바뀔 수 있고, 사람마다 그 위치가 바뀐다.
그렇기에 내가 프로그램 내에서 활동한 내역(데이터)를 다른 사람에게 넘겨줄때, 문제가 발생한다.
동시에 다른 언어들과의 통신할때도, 당연하지만 데이터를 그대로 줄순 없다.
이때 사용하는것이 직렬화이다

데이터를 직렬화하여 바이트의 내용으로 변경하고, 이걸 파일로 저장하거나, 데이터베이스에 업로드하거나, 메모리에 저장할 수 있다.

몇일 전 파일 저장과 관련된 글을 작성하였는데 이때 직렬화가 약간 사용되긴 했다. 다만 보다 간편한 방법들을 오늘 배울 수 있어 이부분을 정리해 보려고 한다

1. PlayerPrefs

PlayerPrefs는 매우 간단한 직렬화 방법이다.

        PlayerPrefs.SetString("PlayerData", saveData);

위 코드를 이용해 string 형 saveData를 저장시킬 수 있다.
string형이기 때문에 각종 데이터를 string으로 저장하되, 여러개를 저장할때 쉼표와 같은 문자로 구분시킨다.
이건 파일을 가져올때(역직렬화 할때) .Split('.')을 이용해 구분시켜줄 수 있다.
간단하게 파일이 저장되지만, 보안성도 약하기 때문에 이건 보통 게임의 환경설정에 쓰인다고 한다.

2. CSV

csv는 엑셀을 통해 수정하기 좋은 파일 구조 형식이다.
엑셀과 다를것이 별로 없고, 쉼표와 \n을 통해 행과 열이 표시된다.
보통 Dictionary를 사용해 확인하거나, List형으로 받아온다고 한다.

데이터를 불러올땐

var csvData = Resources.Load<TextAsset>("CSVData");

과 같은 형식으로 가져올 수 있다.
한번 가져온 내용은 PlayerPrefs처럼 한번 풀어줘야한다.
PlayerPrefs와 매우 유사해보이지만, 이건 수정할때 엑셀을 통해서 편리하게 관리가 가능하다는 점이 큰 장점같다.
텍스트 기반으로 스크립트를 짤 때 매우 유용할 것 같다.

3. XML

과거에는 xml이 직렬화에 많이 사용되었다고 한다.
xml은 무척 복잡하고 어려워 완벽하게 이해하지는 못하였다.
하지만 보다 직관? 적? 이고? 데이터의 계층 구조를 한눈에 볼수 있다는 점은 장점..? 이라고 할수 있을것같다??

    void CreatXML(Player p)
    {
        XmlDocument xmlDoc = new XmlDocument();
        //xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "utf-8", "yes"));

        // 루트 노드
        XmlNode root = xmlDoc.CreateNode(XmlNodeType.Element, "GameData", string.Empty);
        xmlDoc.AppendChild(root);

        // 자식 노드
        XmlNode child = xmlDoc.CreateNode(XmlNodeType.Element, "PlayerData", string.Empty);
        root.AppendChild(child);

        XmlElement nickname = xmlDoc.CreateElement("nickname");
        nickname.InnerText = p.nickname;
        child.AppendChild(nickname);

        XmlElement lv = xmlDoc.CreateElement("lv");
        lv.InnerText = p.lv.ToString();
        child.AppendChild(lv);

        XmlElement hp = xmlDoc.CreateElement("hp");
        hp.InnerText = p.hp.ToString();
        child.AppendChild(hp);

        xmlDoc.Save("./Assets/Resources/GameDatas.xml");

        AssetDatabase.Refresh(); // 에디터 리프레쉬(에디터 나갔다 다시 돌아올 필요 없음)
    }

    void LoadXML()
    {
        var t = Resources.Load<TextAsset>("GameDatas");

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(t.text);

        XmlNodeList nodes = xmlDoc.SelectNodes("GameData/PlayerData");

        XmlNode playerData = nodes[0];

        p.nickname = playerData.SelectSingleNode("nickname").InnerText;
        p.lv = int.Parse(playerData.SelectSingleNode("lv").InnerText);
        p.hp = float.Parse(playerData.SelectSingleNode("hp").InnerText);
    }

진짜 하나도 모르겠다.
다만 각 노드들을 만들어 주고, 그에 따른 데이터를 넣는 그런 구조임을 기억하면 좋을 것 같다.

4. json

json은 정말 편리하고, 유니티에서 지원도 잘되어있는 그런 직렬화 방법이다.
JsonUtility라는 좋은 클래스를 지원하고있다.
Class로 데이터의 구조를 한번 만들어 준 뒤, 상단에 [System.Serializable]을 작성하면 직렬화 준비는 끝난 셈이다.
이때 중요한 것은 class내부의 형식인데, 직렬화가 가능한 것과 불가능한 것들이 정해져있다.
그 조건들은 여기서 보면 좋을 것 같다.
이제 파일을 저장할 땐

var json = JsonUtility.ToJson(data);
File.WriteAllText(Application.persistentDataPath + "/UserData.txt", json);

의 형태로 가능하다.
json으로 만들고, 이걸 파일로 작성하는 단순한 두줄 코드이다.
불러올때도 그렇게 어렵지 않다.

var jsonData = File.ReadAllText(Application.persistentDataPath + "/UserData.txt");
data = JsonUtility.FromJson<UserData>(jsonData);

JsonUtility를 사용해 편하게 가져올 수 있다.

서버 통신에도 자주 사용된다고 했는데, 아직 이부분은 다음 특강을 기대해봐야겠다.

profile
게임개발호소인

0개의 댓글