Unity中文件上传以及下载,获取下载文件大小的解决方案

首先现在Unity插件那么的广泛的情况下,很多东西都不需要自己实现,直接使用第三方插件就可以了,但为什么这里需要自己写,接下来说明原因。

在Unity商城中有很多关于关于网络接口调用的插件,其中有一款叫BestHTTP这款使用比较广泛的插件,不知道朋友们是不是都知道,是不是都有用过,很多功能都已经给你实现好了,你只需要调用就可以了,插件很好用是吧。

以前我也用这个插件,在很多方面的确很好用,但是在个别平台有个很严重的问题,这个插件的调用占用内存会非常高,而且有一定的内存泄露。

在PC和移动端,由于现在硬件设备配置普遍都比较高,所以可能感觉的不会很明显,但在Webgl端,也是我经历之后才在之后的项目中不再使用这款插件的原因。在Unity的Webgl,限制了最多只能使用2048m的缓存,超过这个缓存值,网页就会报异常,到现在我也不知道该怎么解决这个问题,希望有知道的朋友告知一下,谢谢。

继续说原因,在Webgl端使用这个插件会有很明显的内存被大量占用,并且有一定的内存泄露,之前有一个项目,加载场景AB包,提一嘴本身每个平台的AB大小都是不一样的,虽然没比较过所有平台的,但是Webgl的AB包会比PC和移动端的大很多。

加载100m左右场景AB包,使用该插件加载只能加载2-3次就会直接报内存溢出,也就是前面说的超过了2048m的缓存上限。

因此后续就改成用Unity自带的UnityWebRequest类了,使用自带的也会有多占用内存的现象但是比该插件就会好很多,例如加载100m左右的ab能够加载12-15次时,才有可能会出现内存溢出的问题,如果有些数据释放的及时,甚至能加载更多次。

说了一大端的原因,那么接着就进入正题,首先下载,下载有个小问题,就是我们拿不到下载文件的总大小,这里我就提供解决方案,具体的实现根据自身项目使用

解决方案:
1、如果文件保存在对象存储上的,有一个Head请求,可以拿到文件的信息,里面包含了文件大小,但是这需要对象存储开启Head请求的权限
2、后台自己写一个保存文件的总大小,下载前先调用获取文件信息
3、UnityWebRequest中提供了两个数据,一个是progress进度,一个是当前下载量,那么其实可以通过 当前下载量/progress,反推出文件大小,只不过这个方式可能存在误差,但应该误差不会很大,所以如果不想多次请求的话可以使用这种方式

1、通过Head请求获取文件信息(方法使用了异步,使用异步需要扩写异步Task.GetAwaiter(),这方面已经有现成的异步插件了,以从夸克下载地址获取(不定时会更新该插件,如果其他文章中涉及到第三方插件,也会在该地址中提供测试的插件下载):https://pan.quark.cn/s/58004b052787

        public static async void GetDownloadFileSize(string downloadUrl, Action<WebRequetState, UnityWebRequest, ulong, string> outputAction = null, Dictionary<string, string> headers = null)
        {
            using (UnityWebRequest webRequest = UnityWebRequest.Head(downloadUrl))
            {
                if (headers != null)
                {
                    foreach (var info in headers)
                    {
                        webRequest.SetRequestHeader(info.Key, info.Value);
                    }
                }
                webRequest.useHttpContinue = false;
                outputAction?.Invoke(WebRequetState.WebReuqetStart, webRequest, 0, "开始获取文件大小");
                await webRequest.SendWebRequest();
                if (webRequest.result == UnityWebRequest.Result.Success)
                {
                    ulong.TryParse(webRequest.GetResponseHeader("Content-Length"), out ulong size);
                    outputAction?.Invoke(WebRequetState.WebReuqetSucceed, webRequest, size, "获取文件大小成功");
                }
                else
                {
                    Debug.LogWarning(webRequest.result == UnityWebRequest.Result.ConnectionError ? "连接失败" : "获取数据失败" + $"  Method = {webRequest.method}  Code = {webRequest.responseCode}  error = {webRequest.error}");
                    outputAction?.Invoke(WebRequetState.WebReuqetFailed, webRequest, 0, webRequest.error);
                }
            }
        }

2、下载文件的代码(通过协程方式,如果不通过协程,也可以用异步多线程,如果这两个都不使用,那就是主线程的Update去刷新)

    protected virtual System.Collections.IEnumerator DownloadCoroutine()
    {
        using (request = UnityWebRequest.Get(Url))
        {
            request.useHttpContinue = false;
            request.downloadHandler = new DownloadHandlerBuffer();

            var wait = new WaitForEndOfFrame();

            request.SendWebRequest();

            do
            {
                CurrentSize = request.downloadedBytes;

                if (request.downloadProgress > 0.00f)
                {
                    //TotalSize = (ulong)(CurrentSize / request.downloadProgress);

					//TODO:下载进度,可以用来显示进度条
                }
                yield return wait;
            }
            while (!request.isDone);

            if (request.result == UnityWebRequest.Result.Success)
            {
				//下载成功时的操作,通过request.downloadHandler.data获取文件二进制数据
            }
            else
            {
				//下载失败时的操作
            }

            request.Dispose();
        }
    }
}

3、上传文件(可以改成协程,每帧调用显示上传进度)

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="uploadUrl">上传接口路径</param>
        /// <param name="fileName">文件名</param>
        /// <param name="fileData">文件数据</param>
        /// <param name="headers">请求头</param>
        /// <param name="outputAction">回调(上传状态,Request对象,返回数据,Message)</param>
        /// <param name="fileKey">文件key字段</param>
        /// <param name="contentType">内容Type</param>
        public static async void UploadFile(string uploadUrl, string fileName, byte[] fileData, Dictionary<string, string> headers = null, Action<WebRequetState, UnityWebRequest, string, string> outputAction = null, string fileKey = "", string contentType = "")
        {
            List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
            var fileSection = (fileKey == null || fileKey == string.Empty) ? new MultipartFormFileSection(fileName, fileData) : new MultipartFormFileSection(fileKey, fileData, fileName, contentType);
            formData.Add(fileSection);

            using (UnityWebRequest webRequest = UnityWebRequest.Post(uploadUrl, formData))
            {
                if (headers != null)
                {
                    foreach (var info in headers)
                    {
                        webRequest.SetRequestHeader(info.Key, info.Value);
                    }
                }

                webRequest.useHttpContinue = false;

                outputAction?.Invoke(WebRequetState.WebReuqetStart, webRequest, string.Empty, "开始上传");

                await webRequest.SendWebRequest();

                if (webRequest.result == UnityWebRequest.Result.Success)
                {
                    outputAction?.Invoke(WebRequetState.WebReuqetSucceed, webRequest, webRequest.downloadHandler.text, "上传成功");
                }
                else
                {
                    Debug.LogWarning(webRequest.result == UnityWebRequest.Result.ConnectionError ? "连接失败" : "上传失败" + $"  Method = {webRequest.method}  Code = {webRequest.responseCode}  error = {webRequest.error}");
                    outputAction?.Invoke(WebRequetState.WebReuqetFailed, webRequest, webRequest.error, "上传失败");
                }
            }
        }

基础的方法就这些,以后会整理一个专门的工具类脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TenderRain。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值