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
}