using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;
namespace AibisDream.Utility
{
public class CsvUtil
{
// 默认编码
private static readonly Encoding DefaultEncode = Encoding.UTF8;
// 默认分隔符
private const char FieldSeparator = ',';
///
/// 根据平台读取文件内容
///
private static string ReadFileText(string filePath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
// Android 平台需要使用 UnityWebRequest 读取 StreamingAssets
if (filePath.Contains(Application.streamingAssetsPath))
{
// Android 上 StreamingAssets 在 APK 中,需要构建正确的 URL
string url = filePath;
// 确保使用正确的路径分隔符
url = url.Replace("\\", "/");
// 如果路径不包含协议前缀,添加 file://
if (!url.StartsWith("file://") && !url.StartsWith("jar:file://"))
{
// 对于 Android APK 中的文件,使用 jar:file:// 协议
string relativePath = url.Replace(Application.streamingAssetsPath, "").TrimStart('/');
url = "jar:file://" + Application.dataPath + "!/assets/" + relativePath;
}
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
www.SendWebRequest();
// 等待请求完成(同步等待)
while (!www.isDone)
{
// 在主线程中等待
}
if (www.result == UnityWebRequest.Result.Success)
{
return www.downloadHandler.text;
}
else
{
throw new IOException($"无法读取文件: {filePath}, URL: {url}, 错误: {www.error}");
}
}
}
else
{
// 非 StreamingAssets 路径,使用普通文件读取
return File.ReadAllText(filePath, DefaultEncode);
}
#else
// 其他平台直接使用 File 类
return File.ReadAllText(filePath, DefaultEncode);
#endif
}
///
/// 根据平台创建 StreamReader
///
private static StreamReader CreateStreamReader(string filePath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
// Android 平台需要使用 UnityWebRequest 读取 StreamingAssets
if (filePath.Contains(Application.streamingAssetsPath))
{
string fileText = ReadFileText(filePath);
MemoryStream stream = new MemoryStream(DefaultEncode.GetBytes(fileText));
return new StreamReader(stream, DefaultEncode);
}
else
{
// 非 StreamingAssets 路径,使用普通文件读取
return new StreamReader(filePath, DefaultEncode);
}
#else
// 其他平台直接使用 File 类
return new StreamReader(filePath, DefaultEncode);
#endif
}
public static List Read(string filePath)
{
List dataList = new List();
StreamReader reader = null;
try
{
using (reader = CreateStreamReader(filePath))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (line == null) break;
string[] data = line.Split(FieldSeparator);
dataList.Add(data);
}
}
}
catch (Exception ex)
{
foreach (Process process in Process.GetProcesses())
{
if (process.ProcessName.ToUpper().Equals("EXCEL"))
process.Kill();
}
GC.Collect();
Thread.Sleep(50);
Console.WriteLine(ex.StackTrace);
using (reader = CreateStreamReader(filePath))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (line == null) break;
string[] data = line.Split(FieldSeparator);
dataList.Add(data);
}
}
}
finally
{
reader?.Close();
}
return dataList;
}
public static void WriteCsv(string filePath, List dataList)
{
StreamWriter writer = new StreamWriter(filePath, false, DefaultEncode);
foreach (string[] data in dataList)
{
writer.WriteLine(string.Join(FieldSeparator, data));
}
writer.Close();
}
public static List ReadAsBean(string filePath) where T : class
{
// 反射部分
var targetType = typeof(T);
var props = targetType.GetProperties();
// 读取CSV
using var reader = CreateStreamReader(filePath);
// 第一行是注释
reader.ReadLine();
// 第二行作为title
var titles = reader.ReadLine()?.Split(FieldSeparator);
if (titles == null)
{
System.Diagnostics.Debug.WriteLine("csv无标题");
throw new Exception("csv无标题");
}
var res = new List();
// 第二行开始读配置内容
while (!reader.EndOfStream)
{
string newLine = reader.ReadLine();
if (string.IsNullOrEmpty(newLine)) break;
string[] rowData = newLine.Split(FieldSeparator);
if (rowData == null || rowData.Length == 0) continue;
// 转为Bean
var obj = Activator.CreateInstance(targetType);
foreach (var prop in props)
{
string name = prop.Name;
if (!titles.Contains(prop.Name))
continue;
int idx = Array.IndexOf(titles, prop.Name);
prop.SetValue(obj, GetDefaultValue(prop, rowData[idx]));
}
res.Add(obj as T);
}
return res;
}
public static bool ReadAsDataTable(ref DataTable myCsvDt, string filepath)
{
var strPath = filepath; //csv文件的路径
try
{
bool blnFlag = true;
StreamReader reader = CreateStreamReader(strPath);
myCsvDt = new DataTable();
while (reader.ReadLine() is { } strLine)
{
var aryLine = strLine.Split(FieldSeparator);
//第一行是列的名字,给datatable加上列名,
if (blnFlag)
{
blnFlag = false;
var intColCount = aryLine.Length;
#region 序号作为列头
//int col = 0;
//for (int i = 0; i < intColCount; i++)
//{
// col = i + 1;
// mydc = new DataColumn(col.ToString());
// mycsvdt.Columns.Add(mydc);
//}
#endregion
#region 第一行作为列头
for (int i = 0; i < intColCount; i++)
{
myCsvDt.Columns.Add(new DataColumn(aryLine[i]));
}
continue;
#endregion
}
//填充数据并加入到datatable中
myCsvDt.Rows.Add(aryLine);
}
reader.Close();
return true;
}
catch (Exception)
{
return false;
}
}
public static void ExportAsCsv(DataTable dt, string savaPath, string strName)
{
string strPath = savaPath + "\\" + strName; //保存到指定目录下
if (File.Exists(strPath))
{
File.Delete(strPath);
}
//先打印标头
StringBuilder strColu = new StringBuilder();
StringBuilder strValue = new StringBuilder();
StreamWriter sw = new StreamWriter(new FileStream(strPath, FileMode.CreateNew), DefaultEncode);
try
{
for (var i = 0; i <= dt.Columns.Count - 1; i++)
{
strColu.Append(dt.Columns[i].ColumnName);
strColu.Append(FieldSeparator);
}
strColu.Remove(strColu.Length - 1, 1); //移出掉最后一个,字符
sw.WriteLine(strColu);
foreach (DataRow dr in dt.Rows)
{
strValue.Remove(0, strValue.Length); //移出
for (var i = 0; i <= dt.Columns.Count - 1; i++)
{
strValue.Append(dr[i]);
strValue.Append(FieldSeparator);
}
strValue.Remove(strValue.Length - 1, 1); //移出掉最后一个,字符
sw.WriteLine(strValue);
}
sw.Close();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
sw.Close();
}
}
#region 类型转换
private static object GetDefaultValue(PropertyInfo prop, string value)
{
return prop.PropertyType.Name switch
{
"String" => ToNormalString(value),
"Int32" => ToInt32(value),
"Decimal" => ToDecimal(value),
"Single" => ToFloat(value),
"Boolean" => ToBoolean(value),
"DateTime" => ToDateTime(value),
"Double" => ToDouble(value),
_ => ToEnum(value, prop)
};
}
private static object ToEnum(string value, PropertyInfo prop)
{
return prop.PropertyType.BaseType == typeof(Enum) ? Enum.Parse(prop.PropertyType, value) : null;
}
///
/// 转换为Int32
///
private static int ToInt32(string obj)
{
if (string.IsNullOrEmpty(obj)) return 0;
try
{
if (obj.Contains("."))
return (int)Convert.ToSingle(obj);
if (int.TryParse(obj, out var tmp))
return tmp;
}
catch
{
return 0;
}
return 0;
}
///
/// 转换为字符串
///
private static string ToNormalString(string obj)
{
if (obj == null)
return string.Empty;
try
{
return Convert.ToString(obj);
}
catch
{
return string.Empty;
}
}
///
/// 转换为日期
///
private static DateTime ToDateTime(string obj)
{
if (string.IsNullOrEmpty(obj))
{
return Convert.ToDateTime("1970-01-01 00:00:00");
}
try
{
return Convert.ToDateTime(obj);
}
catch
{
return Convert.ToDateTime("1970-01-01 00:00:00");
}
}
///
/// 转换为布尔型
///
private static bool ToBoolean(string obj)
{
if (obj == null) return false;
return obj.ToLower() == "true" || obj == "1";
}
///
/// 转换为十进制数值
///
private static Decimal ToDecimal(string obj)
{
if (obj == null)
{
return 0M;
}
var resultString = Regex.Replace(obj, "[^0-9.]", "");
var result = resultString.Length == 0 ? 0M : decimal.Parse(resultString, CultureInfo.CurrentCulture);
if (obj.StartsWith("-"))
{
result *= -1M;
}
return result;
}
///
/// 转换为双精度.
///
private static double ToDouble(string obj)
{
if (double.TryParse(obj, out var num))
return num;
else
return 0;
}
///
/// 转换为单精度.
///
private static float ToFloat(string value)
{
var normalStr = ToNormalString(value);
if (string.IsNullOrEmpty(normalStr))
{
return 0;
}
if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
return result;
else
return 0;
}
#endregion
}
}