using Cysharp.Threading.Tasks; using System; using System.Collections; using System.Collections.Generic; using System.IO.Compression; using System.IO; using System.Security.Cryptography; using System.Text; using System.Threading; using UnityEngine; using UnityEngine.Networking; public class FileUpLoad { //随机Key,方便查询上传的文件 private static readonly char[] charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray(); public static string GetRandomNum() { byte[] randomBytes = new byte[8]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(randomBytes); } StringBuilder sb = new StringBuilder(8); foreach (byte b in randomBytes) { // 62进制映射(62=26大写+26小写+10数字) sb.Append(charSet[b % 62]); } return sb.ToString(); } #region 配置参数 public static string UploadEndpoint { get; set; } = $"你的日志存放地址"; /// 超时抛出 public static int TimeoutSeconds { get; set; } = 20; /// 压缩枚举 public static System.IO.Compression.CompressionLevel TextCompressionLevel { get; set; } = System.IO.Compression.CompressionLevel.Optimal; /* * ‌NoCompression‌ 不执行压缩操作,直接存储原始数据 需要快速写入但无需压缩的场景‌ ‌ Fastest‌ 快速压缩,牺牲压缩率以提升速度 对实时性要求高的场景(如日志记录)‌ ‌ Optimal‌ 平衡压缩率与速度(默认选项) 通用文件压缩需求(如用户数据存档)‌ ‌ SmallestSize‌ 最大压缩率,牺牲速度以减小文件体积 网络传输或存储空间敏感场景‌ */ #endregion #region 核心上传API /// /// 智能文件上传(支持文本压缩) /// /// 完整文件路径 /// 取消令牌 /// 元组(是否成功,响应数据/错误信息) public static async UniTask<(bool success, string result)> UploadFileAsync( string filePath, CancellationToken ct = default) { try { // 强制主线程执行上下文 await UniTask.SwitchToMainThread(); // 文件基础校验 if (!System.IO.File.Exists(filePath)) return (false, $"文件不存在: {Path.GetFileName(filePath)}"); // 动态处理文件 var (payload, fileName, mime) = await ProcessFile(filePath, ct); // 构建网络请求 using var request = CreateUploadRequest(payload, fileName, mime); var (isSuccess, result) = await ExecuteRequest(request, ct); return (isSuccess, isSuccess ? $"上传成功: {result}" : $"服务器拒绝: {result}"); } catch (Exception ex) when (ex is not OperationCanceledException) { return (false, FormatException(ex)); } } #endregion #region 私有方法 private static async UniTask<(byte[] data, string name, string mime)> ProcessFile( string path, CancellationToken ct) { // 自动识别文本类型 if (IsTextFile(path)) { var compressed = await CompressTextAsync(path, ct); return (compressed.data, compressed.name, "application/zip"); } // 非文本文件直传 var bytes = await System.IO.File.ReadAllBytesAsync(path, ct); return (bytes, Path.GetFileName(path), GetMimeType(Path.GetExtension(path))); } private static UnityWebRequest CreateUploadRequest(byte[] data, string name, string mime) { var form = new WWWForm(); //附加参数 //string tRoId = string.Empty; //form.AddField("roleid", tRoId); //string tServerId = TcpManager.CurServerData != null ? TcpManager.CurServerData.server_id : "0"; //form.AddField("serverId", tServerId); //form.AddField("packageNo", AppEntry.PkgConfig.PackageID); //form.AddField("platform", Common.GetPlatformPath()); //form.AddField("content", mIptContent); //form.AddField("type", 2); //form.AddField("fdtype", mSelectName); form.AddBinaryData("file", data, name, mime); var request = UnityWebRequest.Post(UploadEndpoint, form); request.timeout = TimeoutSeconds; return request; } private static async UniTask<(bool isSuccess, string result)> ExecuteRequest( UnityWebRequest request, CancellationToken ct) { try { var operation = request.SendWebRequest(); while (!operation.isDone && !ct.IsCancellationRequested) { await UniTask.Yield(PlayerLoopTiming.Update, ct); } if (ct.IsCancellationRequested) { request.Abort(); return (false, "用户取消操作"); } return request.result == UnityWebRequest.Result.Success ? (true, request.downloadHandler.text) : (false, $"[{request.responseCode}] {request.error}"); } finally { request.Dispose(); } } #endregion #region 工具方法 private static async UniTask<(byte[] data, string name)> CompressTextAsync( string path, CancellationToken ct) { await using var memStream = new MemoryStream(); using (var archive = new ZipArchive(memStream, ZipArchiveMode.Create, true)) { var entry = archive.CreateEntry(Path.GetFileName(path), TextCompressionLevel); await using (var entryStream = entry.Open()) await using (var fileStream = System.IO.File.OpenRead(path)) { await fileStream.CopyToAsync(entryStream, 81920, ct); } } return (memStream.ToArray(), $"{Path.GetFileNameWithoutExtension(path)}.zip"); } private static bool IsTextFile(string path) { var ext = Path.GetExtension(path).ToLower(); return ext is ".txt" or ".log" or ".csv" or ".json"; } private static string GetMimeType(string ext) => ext switch { ".zip" => "application/zip", ".txt" => "text/plain", ".jpg" => "image/jpeg", _ => "application/octet-stream" }; private static string FormatException(Exception ex) => ex switch { UnityWebRequestException uwrEx => $"网络错误 [{uwrEx.ResponseCode}]: {uwrEx.Message}", IOException ioEx => $"文件系统错误: {ioEx.Message}", UnauthorizedAccessException uaEx => $"权限不足: {uaEx.Message}", _ => $"系统异常: {ex.GetBaseException().Message}" }; #endregion }