내일배움캠프-레벨업세션에서 엑셀 파일을 Json으로 변환하는 기능을 봤는데 
이번 프로젝트에서 그대로 사용하기에는 맞지않다고 느껴서
유니티 내부에서 csv파일을 Json으로 저장하는 기능을 만들어보았다. 

 

📝 CsvToJsonConverter.cs

- 전체코드

public class CsvToJsonConverter : MonoBehaviour
{
    /// <summary>
    /// ***Converter 사용 전 주의사항***
    /// 1. 입력한 string, 클래스명, Recources하위의 csv 데이터 이름이 동일해야합니다.
    /// 2. Recources파일 하위에 csv데이터가 존재해야합니다.
    /// 3. csv 데이터를 파싱해서 사용할 클래스 조건
    ///     (1) 클래스여야합니다.
    ///     (2) ICsvParsable 인터페이스를 구현해야합니다.
    ///     (3) 매개변수가 없는 생성자를 가지고 있어야 합니다.
    ///     : ICsvParsable 인터페이스와 사용예시는 Stage 스크립트를 참고해주세요
    /// </summary>

    [Header("===클래스 이름을 작성해주세요===")]
    public string[] className;

    public void CsvConverByName()
    {
        Debug.Log("CsvConverter메서드입니다");

        for (int i = 0; i < className.Length; i++)
        {
            // 여기서 type은 ? 클래스라고 생각하면 편함 
            // string에 맞는 타입 생성 
            Type type = Type.GetType(className[i]);

            if (type == null)
            {
                Debug.LogError($"해당 클래스({className[i]})를 찾을 수 없습니다.");
                continue;
            }

            if (!typeof(ICsvParsable).IsAssignableFrom(type))
            {
                Debug.LogError($"클래스({className[i]})는 ICsvParsable을 구현해야 합니다.");
                continue;
            }

            // CsvDataParsing<> 클래스의 타입을
            // MakeGeneritType : type으로 제네릭 지정
            // convertype : 즉 CsvDataParsing<클래스명>이 된다
            Type converterType = typeof(CsvDataParsing<>).MakeGenericType(type);

            // CsvDataParsing 인스턴스화 
            // 매개변수는 className[i]
            object converterInstance = Activator.CreateInstance(converterType, className[i]);

            // CsvDataParsing<>의 GetDataArray() 메서드 가져오기 
            MethodInfo method = converterType.GetMethod("GetDataArray");

            if (method != null)
            {
                // GetDataArray 메서드 Invoke
                // return 값은 List<T>이지만 object타입으로 박싱(boxing) 일어남 
                // 원본 데이터 배열 가져오기 (List<T> 타입)
                // 컴파일 타임에는 object, 런타임때는 List<T>
                object dataArray = method.Invoke(converterInstance, null);

                // 원본 타입을 유지한 채 JSON으로 변환
                string json = JsonSerialized.ConvertOriginalListToJson(dataArray, type);

                // 결과 저장
                jsonResults[className[i]] = json;

                // 파일로 저장
                JsonSerialized.SaveJsonToFile(json, className[i]);

                Debug.Log($"{className[i]} 데이터를 성공적으로 변환했습니다.");
            }

        }
    }
}

 

 

- 상세코드

Type type = Type.GetType(className[i]);

클래스 이름을 통해서 클래스 타입을 type변수에 저장한다.

Type converterType = typeof(CsvDataParsing<>).MakeGenericType(type);

CsvDataParsing 클래스의 제네릭 타입을 위에서 지정해준 type(현재 클래스의 타입)으로 설정한다. 

object converterInstance = Activator.CreateInstance(converterType, className[i]);

Reflection의 Activator.CreateInstance를 사용해서 제네릭 클래스인 CsvDataParsing를 인스턴스화 한다.

생성자의 매개변수는 현재 클래스이름 

MethodInfo method = converterType.GetMethod("GetDataArray");

  CsvDataParsing 클래스의 GetDataArray()함수를 MethodInfo에 저장한다 

 

if (method != null)
{
    object dataArray = method.Invoke(converterInstance, null);

  GetDataArray메서드를 실행 

  리턴값은 컴파일 타임에는 object 타입으로 저장되고, 런타임때는 List<T> 타입으로 저장된다

 

    // 원본 타입을 유지한 채 JSON으로 변환
    string json = JsonSerialized.ConvertOriginalListToJson(dataArray, type);

    // 파일로 저장
    JsonSerialized.SaveJsonToFile(json, className[i]);

    Debug.Log($"{className[i]} 데이터를 성공적으로 변환했습니다.");
}

■ JsonSerialized 클래스의 ConvertOriginalListToJson() 메서드를 실행 후 json 문자열을 return받는다

JsonSerialized 클래스의 SaveJsonToFile() 메서드를 실행 후 json 파일을 저장한다. 

 

📝 JsonSerialized.cs

- 전체코드

[SerializeField]
public class ListWrapper<T>
{
    public List<T> values;
}
public static class JsonSerialized
{
    // C:\Users\[user name]\AppData\LocalLow\[company name]\[product name]
    static string savePath = Application.persistentDataPath;

    // 원본 타입의 리스트를 변환하는 메서드 (리플렉션 사용)
    public static string ConvertOriginalListToJson(object dataArray, Type elementType)
    {
        // dataArray는 현재 List<T>
        // 1. 적절한 ListWrapper<tyoe> 타입 생성
        Type wrapperType = typeof(ListWrapper<>).MakeGenericType(elementType);

        // 2. 래퍼 인스턴스 생성
        object wrapper = Activator.CreateInstance(wrapperType);

        // 3. values 필드 가져오기
        FieldInfo valuesField = wrapperType.GetField("values");

        // 4. dataArray를 values 필드에 할당
        // dataArray는 object타입이지만 실제로는 List<T> (매개변수로 List<T>를 넘겼기 때문)
        valuesField.SetValue(wrapper, dataArray);

        // 5. JsonUtility로 직렬화
        return JsonUtility.ToJson(wrapper);
    }

    public static void SaveJsonToFile(string json, string saveFileName)
    {
        try
        {
            string path = Path.Combine(savePath, saveFileName);
            File.WriteAllText(path, json);
            Debug.Log($"{saveFileName}이 저장되었습니다. 경로: {path}");
        }
        catch (Exception ex)
        {
            Debug.LogError($"파일 저장 중 오류 발생: {ex.Message}");
        }
    }
}

 

 

- 상세코드

🔖 ConvertOriginalListToJson() 메서드

    // dataArray는 현재 List<T>
    // 1. 적절한 ListWrapper<tyoe> 타입 생성
    Type wrapperType = typeof(ListWrapper<>).MakeGenericType(elementType);

ListWrapper클래스의 제네릭 타입을 위에서 매개변수의 type(현재 클래스의 타입)으로 설정한다. 

 

    // 2. 래퍼 인스턴스 생성
    object wrapper = Activator.CreateInstance(wrapperType);

 Reflection의 Activator.CreateInstance를 사용해서 제네릭 클래스인 ListWrapper를 인스턴스화 한다.

 

    // 3. values 필드 가져오기
    FieldInfo valuesField = wrapperType.GetField("values");

ListWrapper 클래스의 List<T> 타입의 values변수를 FieldInfo 에 저장한다 

 

    // 4. dataArray를 values 필드에 할당
    // dataArray는 object타입이지만 실제로는 List<T> (매개변수로 List<T>를 넘겼기 때문)
    valuesField.SetValue(wrapper, dataArray);

FieldInfo의 SetValue를 통해서 dataArray를 List<T>에 할당한다

 

    // 5. JsonUtility로 직렬화
    return JsonUtility.ToJson(wrapper);

Json으로 직렬화 후 string을 return 한다 

 

🔖 SaveJsonToFile() 메서드

    string path = Path.Combine(savePath, saveFileName);
    File.WriteAllText(path, json);

json 문자열을 지정한 경로에 , 매개변수로 넘어온 파일이름으로 저장한다 

 

📝 ICsvParsable 인터페이스

public interface ICsvParsable
{
    void Parse(string[] values);
}

 

📝 Stage.cs - 테스트용 클래스 

[System.Serializable]
public class Stage : ICsvParsable
{
    [SerializeField] private int hp;
    [SerializeField] private string name;
    [SerializeField] private List<string> animal;

    public void Parse(string[] values)
    {
        hp = int.Parse(values[0]);
        name = values[1];

        animal = new List<string>();
        string[] temp = values[3].Split('-');
        for (int i = 0; i < temp.Length; i++)
        {
            animal.Add(temp[i]);
        }
    }
}

  [System.Serializable]

             □ 직렬화 하기 위해서 클래스 위에 추가한다

csv를 파싱한 데이터를 필드에 넣기위해서 ICsvParsable 인터페이스를 구현한다

Parse(string[] values)

              필드에 맞게 변수를 형변환해서 필드를 설정한다 

 

📝 CsvJsonButton.cs

[CustomEditor(typeof(CsvToJsonConverter))]
public class CsvJsonButton : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        CsvToJsonConverter mana = (CsvToJsonConverter)target;

        if (GUILayout.Button("Cvs to Json"))
        {
            mana.CsvConverByName();
        }
    }
}

에디터에서 실행하기 위해서 커스텀에디터를 만들어준다

 


사전 준비

🔖 csv에서 파싱할 클래스를 작성한다

🔖 해당 클래스는 반드시 CsvParsable인터페이스를 구현해야한다

🔖 csv 파일 이름 , 클래스 이름, 인스펙터 창에 입력한 클래스 이름이 동일해야한다

🔖 Stage클래스 참고 ! 

 

사용방법 ( 테스트환경 )

1. Resources 폴더 내부에 csv 파일 생성

Stage.csv
0.00MB

 

2. Converter 오브젝트의 리스트에 "Stage"입력 후 "Cvs to Json"버튼 클릭 

3. C:\Users\사용자이름\AppData\LocalLow\DefaultCompany\프로젝트이름

의 경로에 Json파일이 생성되었는지 확인한다 

 


📝 깃허브

https://github.com/kimYouChae/UnityCsvToJsonConverter

 

GitHub - kimYouChae/UnityCsvToJsonConverter

Contribute to kimYouChae/UnityCsvToJsonConverter development by creating an account on GitHub.

github.com

 

+ Recent posts