200 lines
7.1 KiB
C#
200 lines
7.1 KiB
C#
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; } = $"你的日志存放地址";
|
||
|
||
/// <summary> 超时抛出 </summary>
|
||
public static int TimeoutSeconds { get; set; } = 20;
|
||
|
||
/// <summary> 压缩枚举 </summary>
|
||
public static System.IO.Compression.CompressionLevel TextCompressionLevel { get; set; } = System.IO.Compression.CompressionLevel.Optimal;
|
||
|
||
/*
|
||
* NoCompression 不执行压缩操作,直接存储原始数据 需要快速写入但无需压缩的场景
|
||
Fastest 快速压缩,牺牲压缩率以提升速度 对实时性要求高的场景(如日志记录)
|
||
Optimal 平衡压缩率与速度(默认选项) 通用文件压缩需求(如用户数据存档)
|
||
SmallestSize 最大压缩率,牺牲速度以减小文件体积 网络传输或存储空间敏感场景
|
||
*/
|
||
|
||
#endregion
|
||
|
||
#region 核心上传API
|
||
/// <summary>
|
||
/// 智能文件上传(支持文本压缩)
|
||
/// </summary>
|
||
/// <param name="filePath">完整文件路径</param>
|
||
/// <param name="ct">取消令牌</param>
|
||
/// <returns>元组(是否成功,响应数据/错误信息)</returns>
|
||
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
|
||
}
|