Unity/제로부터 구현

비동기 데이터 저장

휘게31 2024. 7. 25. 16:22
728x90

데이터 파일 관리하기

1. 플레이어가 가지고있는 고유 데이터와 맵별로 가지고있는 데이터를 분리

2. 플레이어 데이터와 맵 데이터를 가지고있는 클래스를 비동기로 저장하기

 

 

1. 플레이어가 가지고있는 고유 데이터와 맵별로 가지고있는 데이터를 분리

맵마다 가지고 있는 데이터들이 모두 상이하기 때문에 하나의 데이터파일에서 관리하는 것이 가독성이나 필요한 데이터를 찾는 과정이 더 복잡할 것 같아 플레이어 데이터와 분리.

 

더보기
더보기
더보기
[Serializable]
public class SaveFileData
{
    public SerializableSaveMapDataDictionary<string, MapSaveData> SerializableSaveMapDataDictionary;
    public PlayerSaveData _PlayerSaveData;

    public SaveFileData(SerializableSaveMapDataDictionary<string, MapSaveData> SerializableSaveMapDataDictionary, PlayerSaveData _PlayerSaveData)
    {
        this.SerializableSaveMapDataDictionary = SerializableSaveMapDataDictionary;
        this._PlayerSaveData = _PlayerSaveData;
    }
}

 

 

JsonUtility 에는 딕셔너리를 json 으로 파싱해주는 기능은 없기 때문에 키와 벨류를 리스트로 받아 놓고 딕셔너리 처럼 사용할 수 있게 

SerializableSaveMapDataDictionary 라는 클래스를 만듦,

 

Newtonsoft의 Json.NET 를  사용해 복잡한 구조를 한번에  json 화 시킬 수도 있지만 라이브러리를 사용하지않고 직접 관리 하고 싶었음

더보기
더보기
더보기
[Serializable]
public class SerializableSaveMapDataDictionary<TKey, TValue>
{
    [SerializeField]
    private List<TKey> keys = new List<TKey>();
    [SerializeField]
    private List<TValue> values = new List<TValue>();

    public void Add(TKey key, TValue value)
    {
        if (keys.Contains(key))
        {
            Debug.LogWarning($"Key {key} already exists. Value will not be added.");
            return;
        }

        keys.Add(key);
        values.Add(value);
    }

    public Dictionary<TKey, TValue> ToDictionary()
    {
        Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();

        for (int i = 0; i < keys.Count; i++)
        {
            if (dictionary.ContainsKey(keys[i]))
            {
                Debug.LogWarning($"Duplicate key {keys[i]} found during ToDictionary conversion. Skipping.");
                continue;
            }

            dictionary[keys[i]] = values[i];
        }

        return dictionary;
    }

    public void FromDictionary(Dictionary<TKey, TValue> dictionary)
    {
        keys.Clear();
        values.Clear();

        foreach (var kvp in dictionary)
        {
            keys.Add(kvp.Key);
            values.Add(kvp.Value);
        }
    }

}

 

PlayerSaveData는 말그대로 플레이어가 가지고 있는 고유 데이터들을 모아놓은 클래스,

맵과 관련된 데이터는 SerializableSaveMapDataDictionary 를 통해 가져오고

플레이어와 관련된 데이터는 PlayerSaveData로

 

 

 

2. 플레이어 데이터와 맵 데이터를 가지고있는 클래스를 비동기로 저장하기

 

더보기
더보기
더보기
 public async Task Save_SaveFile()
    {
        _SaveFileData.SerializableSaveMapDataDictionary.FromDictionary(dic);
       
        string json = JsonUtility.ToJson(_SaveFileData);
        //File.WriteAllText(filePath, json);
        await WriteTextAsync(filePath, json);
        Debug.Log("Data Saved to " + filePath);
    }

  private async Task WriteTextAsync(string path, string content)
    {
        byte[] encodedText = Encoding.UTF8.GetBytes(content);

        using (FileStream sourceStream = new FileStream(path,
            FileMode.Create, FileAccess.Write, FileShare.None,
            bufferSize: 4096, useAsync: true))
        {
            await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
        };
    }

Task 를 통해 비동기로 데이터를 처리하게 해주었는데 처음에는 File.WriteAllText() 을 통해 간단하게 json 파일을 저장해줬는데, 데이터 저장은 비동기로 처리하는게 더 좋을 것 같아서 FileStream 으로 비동기 처리를 해줌.

 

FileStream은 더 복잡하고 세밀한 파일 작업을 필요로 할 때 사용

- 파일에 대한 다양한 읽기 및 쓰기 작업을 지원

- 버퍼 크기를 지정

- 시스템 자원을 직접적으로 관리할 수 있으며, IDisposable 인터페이스를 구현하여 자원 해제를 자동으로 처리

File.WriteAllText()는 간단한 문자열 기록 작업을 빠르게 수행할 때 적합

- 내부적으로 FileStream을 사용하지만, 파일 열기와 닫기 작업을 자동으로 처리

- 파일 스트림의 세부 사항을 신경 쓸 필요가 없음

 

 

using 문의 경우 자원관리를 간편하게 해주는 구문으로 FileStream 을 생성하고 사용 후 자동으로 해당 객체를 정리해줌.

1.FileStream 객체가 using 블록 안에 생성

2.sourceStream 객체로 비동기 데이터 처리,

  •  new FileStream(경로, 파일 생성 모드, 파일 액세스 권한, 파일을 열 때 다른 프로세스가 해당 파일에 대해 어떤 액세스를 할 수 있는지를 지정,파일을 읽거나 쓸 때 사용하는 버퍼의 크기를 바이트 단위로 지정,비동기 작업을 사용할지 여부

3.using 블록이 끝나면 sourceStream 객체의 Dispose 메서드가 자동으로 호출, FileStream이 사용하는 파일 핸들을 닫고, 관련된 시스템 자원을 해제.

728x90