데이터를 JSON 형태로 저장 및 로드할 수 있는 기능을 구현해보자.
먼저 직렬화할 데이터 타입을 만들어야 하는데 여기서 중요한 점은 위에 [Serializable]
속성을 추가하여 직렬화 가능하게 만들어야 한다는 것이다. 아래 '스크립트 직렬화' Unity 문서에서 자세한 정보를 확인할 수 있다.
지원되는 타입: JSON 시리얼라이저 API는 MonoBehaviour 서브클래스, ScriptableObject 서브 클래스, 또는 [Serializable] 속성이 있는 일반 클래스/구조체를 지원합니다. 링크
단일 데이터는 유니티에 내장되어 있는 JsonUtility
클래스를 통해 쉽게 직렬화/역직렬화 할 수 있다.
[Serializable]
public class Player
{
public string playerId;
public string playerLoc;
public string playerNick;
}
Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";
//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance, true);
Debug.Log(playerToJson);
뒤에 true
를 붙여 주면 아래와 같이 깔끔하게 포맷팅하여 데이터를 직렬화할 수 있다.
{
"playerId": "8484239823",
"playerLoc": "Powai",
"playerNick": "Random Nick"
}
역직렬화는 JsonUtility.FromJson()
함수를 이용할 수 있다.
string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = JsonUtility.FromJson<Player>(jsonString);
Debug.Log(player.playerLoc);
string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = (Player)JsonUtility.FromJson(jsonString, typeof(Player));
Debug.Log(player.playerLoc);
타입을 템플릿 형태로 <>
꺾쇠에 담아 전달하는 방법, 또는 두 번째 인자로 전달하는 방법 모두 가능하다.
Json 데이터는 기본적으로 키-밸류 형식을 가져야 하므로 배열 자체를 바로 포함할 수 없고, 어떤 키 값을 하나 만들고 거기에 대응되는 밸류에 포함시키는 방식을 사용한다.
이 작업을 간편하게 할 수 있는 스니펫을 사용할 수 있다.
public static class JsonHelper
{
public static T[] FromJson<T>(string json)
{
Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
return wrapper.Items;
}
public static string ToJson<T>(T[] array)
{
Wrapper<T> wrapper = new Wrapper<T>();
wrapper.Items = array;
return JsonUtility.ToJson(wrapper);
}
public static string ToJson<T>(T[] array, bool prettyPrint)
{
Wrapper<T> wrapper = new Wrapper<T>();
wrapper.Items = array;
return JsonUtility.ToJson(wrapper, prettyPrint);
}
[Serializable]
private class Wrapper<T>
{
public T[] Items;
}
}
이 코드는 기존의 배열 형식의 데이터를 Wrapper
라는 새로운 데이터에 존재하는 Items
키의 밸류로 만들어서 하나의 Json 파일로 만들 수 있게 한다.
이제 이 JsonHelper
를 사용해서 간편하게 직렬화할 수 있다.
Player[] playerInstance = new Player[2];
playerInstance[0] = new Player();
playerInstance[0].playerId = "8484239823";
playerInstance[0].playerLoc = "Powai";
playerInstance[0].playerNick = "Random Nick";
playerInstance[1] = new Player();
playerInstance[1].playerId = "512343283";
playerInstance[1].playerLoc = "User2";
playerInstance[1].playerNick = "Rand Nick 2";
//Convert to JSON
string playerToJson = JsonHelper.ToJson(playerInstance, true);
Debug.Log(playerToJson);
역직렬화도 쉽게 가능하다.
string jsonString = "{\r\n \"Items\": [\r\n {\r\n \"playerId\": \"8484239823\",\r\n \"playerLoc\": \"Powai\",\r\n \"playerNick\": \"Random Nick\"\r\n },\r\n {\r\n \"playerId\": \"512343283\",\r\n \"playerLoc\": \"User2\",\r\n \"playerNick\": \"Rand Nick 2\"\r\n }\r\n ]\r\n}";
Player[] player = JsonHelper.FromJson<Player>(jsonString);
Debug.Log(player[0].playerLoc);
Debug.Log(player[1].playerLoc);
json string을 Wrapper
형식, 즉 'Items' 라는 키값이 있는 형식으로 변형한 후 리턴한다.
만약 갖고 있는 json string이 앞에 Items:
라는 키값이 아니라면, 수동으로 앞에 Items
라는 키값을 가지는 새로운 json으로 변형한 후 사용할 수 있다.
string fixJson(string value)
{
value = "{\"Items\":" + value + "}";
return value;
}
string jsonString = fixJson(yourJsonFromServer);
Player[] player = JsonHelper.FromJson<Player>(jsonString);
이제 런타임에서 만든 Json 파일을 로컬에 저장해보는 작업이다.
먼저 간단한 데이터 형식을 만든다.
using System;
[Serializable]
public class InputEntry
{
public int A;
public int B;
public InputEntry(int A, int B)
{
this.A = A;
this.B = B;
}
}
FileHandler
라는 이름의 static class를 하나 만들고 모든 기능을 구현하기로 하고, 먼저 입력부터 진행해보자
public static class FileHandler
{
public static void SaveToJSON<T>(List<T> listToSave, string fileName)
{
string filePath = GetFilePath(fileName);
Debug.Log(filePath);
string serializedData = JsonHelper.ToJson<T>(listToSave.ToArray(), true);
WriteToFile(filePath, serializedData);
}
private static string GetFilePath(string fileName)
{
return Application.persistentDataPath + "/" + fileName;
}
private static void WriteToFile(string filePath, string contentToSave)
{
FileStream fileStream = new FileStream(filePath, FileMode.Create); // 새 파일스트림 생성. 만약 이미 존재한다면 덮어쓰기
using (StreamWriter writer = new StreamWriter(fileStream))
{
writer.Write(contentToSave);
}
}
}
SaveToJSON()
함수는 이전에 보았던 JsonHelper
를 통해 Json 형식의 파일을 string으로 만드는 과정을 담고 있다.
GetFilePath()
함수는 데이터를 저장할 경로를 지정하는 것으로, 파일 위치는 상관없으나 Application.persistentDataPath
에 저장한다.
WriteToFile
은 실질적으로 파일에 입력하는 과정으로, 파일스트림을 만들고 StreamWriter
를 만들어서 진행한다.
그리고 버튼을 하나 만들어 런타임에서 랜덤한 숫자쌍을 통해 InputEntry
를 만들도록 한다. 그리고 이것을 FileHandler에 전달한다.
public class InputHandler : MonoBehaviour
{
[SerializeField] private Button btn;
private List<InputEntry> _entries = new List<InputEntry>();
public void AddToEntries()
{
_entries.Add(new InputEntry(Random.Range(0, 100), Random.Range(0, 100)));
FileHandler.SaveToJSON<InputEntry>(_entries, "JsonSavedData.json");
}
}
버튼을 클릭하면 위 그림과 같이 로그가 찍힌 것을 볼 수 있고 해당 위치로 가서 파일을 열어 보면
Json 형태로 파일이 저장된 것을 볼 수 있다.
물론 버튼을 여러 번 누르면 여러 데이터가 저장된다.
파일로부터 읽어오는 과정도 입력과 비슷하게 진행된다.
public static List<T> ReadFromJSON<T>(string fileName)
{
string content = ReadFromFile(GetFilePath(fileName));
if (string.IsNullOrEmpty(content) || content == "{}")
{
return new List<T>();
}
return JsonHelper.FromJson<T>(content).ToList(); // System.Linq 임포트 필요
}
private static string ReadFromFile(string filePath)
{
if (File.Exists(filePath))
{
using (StreamReader reader = new StreamReader(filePath))
{
string content = reader.ReadToEnd();
return content;
}
}
return "";
}
이러면 기존에 만들어졌던 파일에다가 내용을 추가할 수 있다.
public class InputHandler : MonoBehaviour
{
[SerializeField] private Button btn;
private List<InputEntry> _entries = new List<InputEntry>();
private void Start()
{
_entries = FileHandler.ReadFromJSON<InputEntry>("JsonSavedData.json");
}
public void AddToEntries()
{
_entries.Add(new InputEntry(Random.Range(0, 100), Random.Range(0, 100)));
FileHandler.SaveToJSON<InputEntry>(_entries, "JsonSavedData.json");
}
}
시작할 때 기존의 파일을 읽어오고 거기에 추가하여 저장할 수 있도록 한다.
예를 들어 79, 84 쌍의 데이터를 먼저 만들어 놓고, 실행 후 버튼을 눌러 새 데이터를 넣으면,
entries
배열을 가지고 Json 파일을 만들어 새로 저장한 결과를 볼 수 있다.https://www.youtube.com/watch?v=KZft1p8t2lQ
https://stackoverflow.com/questions/36239705/serialize-and-deserialize-json-and-json-array-in-unity