FileUpload/Assets/Scripts/FileUpLoad.cs
2025-02-27 16:14:18 +08:00

200 lines
7.1 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}