유니티 JSON 파일 저장 및 불러오기(1)
유니티 기초 부분에서는 유니티의 PlayerPrefs를 사용하여 데이터를 저장 및 불러오기에 대하여 다루었다.
PlayerPrefs는 int, float, string 형식을 저장 및 불러오기를 할 수 있다. 간단한 데이터를 저장 및 공유하기에는 매우 유용하다.
프로그램은 다양한 자료 구조를 사용하여, 프로그램에 맞는 여러 종류의 데이터를 저장 및 관리를 한다. PlayerPrefs는 리스트와 같은 자료 구조에 대응하기에는 충분하지 않다. 가능은 하다. 단지, 더 많은 노력이 요구된다.
PlayerPrefs은 아래에 글에서 다룬다.
복잡한 구조를 가진 데이터를 저장 및 불러오는 방법은 다양하다. 텍스트 형식을 사용하여, 원하는 형태로 저장을 할 수도 있으며, JSON, XML, CSV 파일 등을 사용하여 데이터를 저장할 수 있다.
본 글에서는 표준 포맷 중의 하나인 JSON을 사용하여 데이터를 저장하고 불러오는 기능을 구현한다.
직렬화(역직렬화)는 데이터 구조를 재구성하여, 데이터를 공유 가능한 형태로 변환(역변환)하는 과정이다.
JSON과 같은 표준 포맷으로 정의하면, 네트워크를 사용해 서버로 전송하거나, 다른 플랫폼과 연동이 용이하다.
- 직렬화 : Serialization
- 역직렬화 : Deserialization
1. JSON ( JavaScript Object Notation )
JSON은 이름 : 값 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다 (출처 : JSON.org). JSON은 프로그래밍 언어와 플랫폼에 독립적이다. 이는 다양한 플랫폼 간의 데이터를 교환하는데 매우 유용하여, 대부분의 플랫폼은 JSON을 제공하고 있다.
유니티는 또한 JSON을 지원하기 위한 JsonUtility 클래스를 제공하고 있다. JsonUtility 클래스는 객체, 사용자 정의 클래스(데이터)를 Json 형식으로 변환(Json 직렬화 )및 Json 형식을 객체, 사용자 정의 클래스로 변환(Json 역직렬화)하는 기능을 제공한다.
2. .net Json
Unity에서 newtonsoft.Json을 사용하여, JSON을 사용할 수 있다.
사용 방법 및 연동은 아래의 링크를 참조한다.
docs.microsoft.com/ko-kr/visualstudio/gamedev/unity/unity-scripting-upgrade
C# JSON 사용 방법
docs.microsoft.com/ko-kr/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-5-0
3. JsonUtility
JsonUtility는 기본형 또는 배열 등과 같은 다른 타입을 직접 API로 전달하여, JSON으로 전환할 수 없다(Unity documents). 이러한 타입을 전환하기 위해서는 class 또는 struct를 사용하여 데이터를 정의하고, 이를 JsonUtility를 이용해, JSON으로 변환해야 한다.
※ JsonUtility는 직접적으로 배열, 리스트 등의 형식을 변환할 수 없다. 하지만 Wrapping Class (class, struct ) 내부에 정의된 클래스, 배열, 리스트 등의 형식은 JsonUtility에서 JSON으로 변환해준다.
주로 데이터의 관리는 Class나 Struct를 만들고 이를 리스트, 배열 등의 자료구조로 관리한다.
사용자 정의 클래스의 리스트를 JSON으로 변환하기 위해 다음의 두 가지를 주의하여 사용할 것을 권장한다.
사용자 정의 클래스는 Serializable 필드로 설정한다.
using System;
[Serializable]
public class MyDataClass{
}
또는
[System.Serializable]
public class MyDataClass{
}
컨테이너 클래스 (Wrapping class)내부 변수에 get set 프로퍼티를 설정하지 않는다.
public class MyJsonContainer{
public int lv {get; set;}
public List<MydataClass> myDataList {get; set;}
// 위와 같은 형식을 설정할 경우 변환되지 않는다.
}
MyJsonContainer 클래스는 저장할 데이터를 포장하기 위한 용도이다.
using System;
using UnityEngine;
public class MyJsonContainer
{
public string myData;
public int level;
public float exp;
public List<string> myList;
public MyDataClass myData;
public List<MydataClass> myDataClasses;
}
[Serializable]
public class MyDataClass
{
public int index;
public double gold;
public string description;
}
3.1 데이터 정의
JsonUtility는 ToJson()을 사용하여 변환(직렬화), FromJson()을 사용하여 역변환(역직렬화)한다.
JSON으로의 변환을 위해 클래스를 정의한다.
using UnityEngine;
public class MyJsonContainer
{
public string myData;
public int level;
public float exp;
// ...
}
3.2 JsonUtility.ToJson()
JsonUtility의 ToJson(object data, bool prettyPrint) 사용하여, 데이터 클래스를 JSON으로 변환한다.
첫 번째 매개변수는 JSON 변환을 위한 데이터이다.
두 번째 매개변수는 영어 prettyPrint 의미 그대로 인간이 더 읽기 쉽도록 줄 변환(\n)을 추가한 형식이다.
using UnityEngine;
public class JsonExample : MonoBehaviour
{
MyJsonContainer jsonContainer;
// Start is called before the first frame update
void Start()
{
jsonContainer = new MyJsonContainer();
jsonContainer.myData = "Examples";
jsonContainer.level = 1;
jsonContainer.exp = 100.0f;
string json = JsonUtility.ToJson(jsonContainer);
Debug.Log(json);
}
}
3.3 JsonUtility.FromJson()
JsonUtility의 FromJson<Object Type>(string json) 사용하여, Json을 변환하여 데이터 클래스로 구성한다.
using UnityEngine;
public class JsonExample : MonoBehaviour
{
MyJsonContainer jsonContainer;
// Start is called before the first frame update
void Start()
{
jsonContainer = new MyJsonContainer();
jsonContainer.myData = "Examples";
jsonContainer.level = 1;
jsonContainer.exp = 100.0f;
string json = JsonUtility.ToJson(jsonContainer);
MyJsonContainer myJson = JsonUtility.FromJson<MyJsonContainer>(json);
}
}
4. File IO
3장에서는 JsonUtility을 사용하여 JSON으로 변환하는 방법에 대해서 기술하였다. 실제 저장이 이루어진 것은 아니며, JSON으로 변환을 한 것이다. 이번 장에서는 JSON을 파일로 저장하고 불러오는 기능을 구현한다.
JsonUtility를 사용한 JSON 변환은 string 형태로 변환이 이루어진다. JSON으로 변환된 string을 파일로 저장하고 불러온다.
DataSaveText() 함수를 구현하고, 모든 데이터 타입을 입력받기 위해, 형식을 T 형식으로 선언한다. T는 C#에서 제공하는 모든 데이터 타입을 입력받기 위한 형식 매개변수이다.
Application.persistentDataPath를 사용해 저장 위치를 설정한다.
Window는 아래에 파일을 저장한다.
- C:\Users\사용자\AppData\LocalLow\DefaultCompany
Android는 아래에 파일을 저장한다.
- data/data/app_name/
4.1 저장
File.WriteAllText(path, json)를 사용해 JSON 형식의 string을 파일에 텍스트로 저장한다.
JSON을 Test.text파일로 저장하는 예제이다.
using System.IO;
using UnityEngine;
public class JsonSaveLoad : MonoBehaviour
{
MyJsonContainer jsonContainer;
// Start is called before the first frame update
void Start()
{
jsonContainer = new MyJsonContainer();
jsonContainer.myData = "Examples";
jsonContainer.level = 1;
jsonContainer.exp = 100.0f;
DataSaveText(jsonContainer, "Test.text");
}
public class MyJsonContainer
{
public string myData;
public int level;
public float exp;
}
public void DataSaveText<T>(T data, string _fileName)
{
try
{
string json = JsonUtility.ToJson(data, true);
if (json.Equals("{}"))
{
Debug.Log("json null");
return;
}
string path = Application.persistentDataPath + "/" + _fileName;
File.WriteAllText(path, json);
Debug.Log(json);
}
catch (FileNotFoundException e)
{
Debug.Log("The file was not found:" + e.Message);
}
catch (DirectoryNotFoundException e)
{
Debug.Log("The directory was not found: " + e.Message);
}
catch (IOException e)
{
Debug.Log("The file could not be opened:" + e.Message);
}
}
}
4.2 불러오기
File의 ReadAllText()를 사용하여 파일로부터 텍스트를 읽어온다.
string json = File.ReadAllText(path)
읽어 들인 JSON을 JsonUtility를 사용해, T 형식의 데이터로 변환하고 이를 반환하도록 구성한다.
정상적으로 JSON에서 T 형식으로 변환이 이루어지지 않으면, default 형을 반환한다.
Test.text로 저장한 데이터를 불러오는 예제이다.
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
public class DataSaveLoad : MonoBehaviour
{
MyJsonContainer jsonContainer;
// Start is called before the first frame update
void Start()
{
MyJsonContainer myJsonContainer = DataLoadText<MyJsonContainer>("Test.text");
Debug.Log(myJsonContainer.myData + myJsonContainer.level + myJsonContainer.exp);
}
public class MyJsonContainer
{
public string myData;
public int level;
public float exp;
}
public T DataLoadText<T>( string _fileName)
{
try
{
string path = Application.persistentDataPath + "/" + _fileName;
if (File.Exists(path))
{
string json = File.ReadAllText(path);
Debug.Log(json);
T t = JsonUtility.FromJson<T>(json);
return t;
}
}
catch (FileNotFoundException e)
{
Debug.Log("The file was not found:" + e.Message);
}
catch (DirectoryNotFoundException e)
{
Debug.Log("The directory was not found: " + e.Message);
}
catch (IOException e)
{
Debug.Log("The file could not be opened:" + e.Message);
}
return default;
}
}
5. 이진 파일 형식으로 JSON 저장 및 불러오기
이진 파일 형식은 아래의 글에서 다룹니다.
참조
docs.unity3d.com/kr/2019.4/Manual/JSONSerialization.html