[ADD] CSV Loader 초안 완료

This commit is contained in:
이정수 2025-05-17 16:50:41 +09:00
parent c1cbd2c3ff
commit 5db096060e
2 changed files with 129 additions and 0 deletions

View File

@ -0,0 +1,118 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// CSV 데이터를 다양한 소스에서 Pull 방식으로 로드할 수 있는 클래스입니다.
/// 호출 측에서 MoveNext()를 통해 처리 타이밍을 제어하세요.
/// </summary>
public static class CSVLoader
{
/// <summary>CSV 파싱 로직 정의</summary>
public interface IParser<T>
{
T Parse(string[] columns);
}
/// <summary>로딩 진행 상태 메타데이터</summary>
public struct Progress
{
public int TotalRows;
public int RowsLoaded;
}
/// <summary>URL(HTTP)로부터 다운로드하여 파싱</summary>
public static IEnumerator<Progress> Download<T>(string url,
IParser<T> parser,
List<T> outList)
{
using var uwr = UnityWebRequest.Get(url);
var operation = uwr.SendWebRequest();
// 요청이 완료될 때까지 대기 (Progress 타입 반환은 요청 상태 표시용)
while (!operation.isDone)
{
yield return new Progress { TotalRows = 0, RowsLoaded = 0 };
}
if (uwr.result != UnityWebRequest.Result.Success)
{
Logger.LogError($"CSVLoader: Download failed '{url}': {uwr.error}");
yield break;
}
string text = uwr.downloadHandler.text;
foreach (var prog in ProcessText(text, parser, outList))
yield return prog;
}
/// <summary>절대 경로의 파일을 읽어 파싱</summary>
public static IEnumerator<Progress> LoadFromFile<T>(string filePath,
IParser<T> parser,
List<T> outList)
{
if (!File.Exists(filePath))
{
Logger.LogError($"CSVLoader: File not found '{filePath}'");
yield break;
}
string text = File.ReadAllText(filePath);
foreach (var prog in ProcessText(text, parser, outList))
yield return prog;
}
/// <summary>StreamingAssets 내 상대 경로 또는 URL로부터 로드</summary>
public static IEnumerator<Progress> LoadFromStreamingAssets<T>(string relativePath,
IParser<T> parser,
List<T> outList)
{
string fullPath = Path.Combine(Application.streamingAssetsPath, relativePath);
if (fullPath.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
var downloadEnum = Download(fullPath, parser, outList);
while (downloadEnum.MoveNext())
yield return downloadEnum.Current;
}
else
{
var fileEnum = LoadFromFile(fullPath, parser, outList);
while (fileEnum.MoveNext())
yield return fileEnum.Current;
}
}
/// <summary>Resources 폴더 내 TextAsset로부터 로드</summary>
public static IEnumerator<Progress> LoadFromResources<T>(string resourcePath,
IParser<T> parser,
List<T> outList)
{
var ta = Resources.Load<TextAsset>(resourcePath);
if (ta == null)
{
Logger.LogError($"CSVLoader: Resource not found '{resourcePath}'");
yield break;
}
string text = ta.text;
foreach (var prog in ProcessText(text, parser, outList))
yield return prog;
}
/// <summary>텍스트를 실제 파싱하여 Progress를 반환하는 내부 모듈</summary>
static IEnumerable<Progress> ProcessText<T>(string text,
IParser<T> parser,
List<T> outList)
{
var lines = text.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
int total = lines.Length;
// 첫 번째 줄은 헤더이므로 무시
// 두 번째 줄은 설명이므로 무시
for (int i = 2; i < total; i++)
{
var cols = lines[i].TrimEnd('\r').Split(',');
outList.Add(parser.Parse(cols));
yield return new Progress { TotalRows = total, RowsLoaded = i + 1 };
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1b37f2c717edfd748bf3173c734fee71
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: