Unity3D 更新文件下载器

使用说明:

1)远端更新服务器目录

Package

  |----list.txt

  |----a.bundle

  |----b.bundle

2)list.txt是更新列表文件

格式是

a.bundle|res/a.bundle

b.bundle|res/b.bundle

(a.bundle是要拼的url,res/a.bundle是要被写在cache的路径)

3)使用代码

var downloader = gameObject.GetComponent<PatchFileDownloader>();
        if (null == downloader)
        {
            downloader = gameObject.AddComponent<PatchFileDownloader>();
        }
        downloader.OnDownLoading = (n, c, file, url) =>
        {
            Debug.Log(url);
        };
        downloader.OnDownLoadOver =(ret)=>{
            Debug.Log("OnDownLoadOver  "+ret.ToString());
        };
        downloader.Download("http://192.168.1.103:3080/Package/", "list.txt");

//更新文件下载器

using System;
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;

//更新文件下载器
public class PatchFileDownloader : MonoBehaviour
{

    //每个更新文件的描述信息
    protected class PatchFileInfo
    {
        // str 的格式是 url.txt|dir/a.txt        url.txt是要拼的url,dir/a.txt是要被写在cache的路径
        public PatchFileInfo(string str)
        {
            Parse(str);

        }

        //解析
        protected virtual void Parse(string str)
        {
            var val = str.Split(‘|‘);
            if (1 == val.Length)
            {
                PartialUrl = val[0];
                RelativePath = val[0];
            }
            else if (2 == val.Length)
            {
                PartialUrl = val[0];
                RelativePath = val[1];
            }
            else
            {
                Debug.Log("PatchFileInfo parse error");
            }
        }

        //要被拼接的URL
        public string PartialUrl { get; private set; }

        //文件相对目录
        public string RelativePath { get; private set; }
    }

    public delegate void DelegateLoading(int idx, int total, string bundleName, string path);
    public delegate void DelegateLoadOver(bool success);

    //正在下载中回掉
    public DelegateLoading OnDownLoading;

    //下载完成回掉
    public DelegateLoadOver OnDownLoadOver;

    //总共要下载的bundle个数
    private int mTotalBundleCount = 0;

    //当前已下载的bundle个数
    private int mBundleCount = 0;

    //开始下载
    public void Download(string url,string dir)
    {
        mBundleCount = 0;
        mTotalBundleCount = 0;
        StartCoroutine(CoDownLoad(url, dir));
    }

    //下载Coroutine
    private IEnumerator CoDownLoad(string url, string dir)
    {
        //先拼接URL
        string fullUrl = Path.Combine(url, dir);

        //获得要更新的文件列表
        List<string> list = new List<string>();

        //先下载列表文件
        using (WWW www = new WWW(fullUrl))
        {
            yield return www;

            if (www.error != null)
            {
                //下载失败
                if (null != OnDownLoadOver)
                {
                    try
                    {
                        OnDownLoadOver(false);
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(e.Message);
                    }
                }

                Debugger.LogError(string.Format("Read {0} failed: {1}", fullUrl, www.error));
                yield break;
            }

            //读取字节
            ByteReader reader = new ByteReader(www.bytes);

            //读取每一行
            while (reader.canRead)
            {
                list.Add(reader.ReadLine());
            }

            if (null != www.assetBundle)
            {
                www.assetBundle.Unload(true);
            }

            www.Dispose();
        }

        //收集所有需要下载的
        var fileList = new List<PatchFileInfo>();
        for (int i = 0; i < list.Count; i++)
        {
            var info = new PatchFileInfo(list[i]);

            if (!CheckNeedDownload(info))
            {
                continue;
            }

            fileList.Add(info);
        }

        mTotalBundleCount = fileList.Count;

        //开始下载所有文件
        for (int i = 0; i < fileList.Count; i++)
        {
            var info = fileList[i];

            var fileUrl = Path.Combine(url, info.PartialUrl);

            StartCoroutine(CoDownloadAndWriteFile(fileUrl, info.RelativePath));
        }

        //检查是否下载完毕
        StartCoroutine(CheckLoadFinish());
    }

    //检查是否该下载
    protected virtual bool CheckNeedDownload(PatchFileInfo info)
    {

        return true;
    }

    //下载并写入文件
    private IEnumerator CoDownloadAndWriteFile(string url,string filePath)
    {
        var fileName = Path.GetFileName(filePath);

        using (WWW www = new WWW(url))
        {
            yield return www;

            if (www.error != null)
            {
                Debugger.LogError(string.Format("Read {0} failed: {1}", url, www.error));
                yield break;
            }

            var writePath = CreateDirectoryRecursive(filePath) + "/" + fileName;

            FileStream fs1 = File.Open(writePath, FileMode.OpenOrCreate);
            fs1.Write(www.bytes, 0, www.bytesDownloaded);
            fs1.Close();

            //Debug.Log("download  " + writePath);
            if (null != www.assetBundle)
            {
                www.assetBundle.Unload(true);
            }
            www.Dispose();

            mBundleCount++;

            if (null != OnDownLoading)
            {
                try
                {
                    OnDownLoading(mBundleCount, mTotalBundleCount, writePath, url);
                }
                catch (Exception e)
                {
                    Debug.LogError(e.Message);
                }
            }
        }
    }

    //递归创建文件夹
    public static string CreateDirectoryRecursive(string relativePath)
    {
        var list = relativePath.Split(‘/‘);
        var temp = Application.temporaryCachePath;
        for (int i=0;i<list.Length-1;i++)
        {
            var dir = list[i];
            if (string.IsNullOrEmpty(dir))
            {
                continue;
            }
            temp += "/" + dir;
            if (!Directory.Exists(temp))
            {
                Directory.CreateDirectory(temp);
            }
        }

        return temp;
    }

    //清空某个目录
    public static void CleanDirectory(string relativePath)
    {

        var fallPath = Path.Combine(Application.temporaryCachePath, relativePath);
        if (string.IsNullOrEmpty(relativePath))
        {
            Caching.CleanCache();
            return;
        }

        var dirs = Directory.GetDirectories(fallPath);
        var files = Directory.GetFiles(fallPath);

        foreach (var file in files)
        {
            File.Delete(file);
        }

        foreach (var dir in dirs)
        {
            Directory.Delete(dir, true);
        }

        Debug.Log("CleaDirectory " + fallPath);
    }

    //检查是否已经下载完毕
    IEnumerator CheckLoadFinish()
    {
        while (mBundleCount < mTotalBundleCount)
        {
            yield return null;
        }

        if (null != OnDownLoadOver)
        {
            try
            {
                OnDownLoadOver(true);
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
            }
        }
    }
}
时间: 2024-11-17 13:46:48

Unity3D 更新文件下载器的相关文章

Android多线程文件下载器

本应用实现的是输入文件的网络的地址,点击按钮开始下载,下载过程中有进度条和后面的文本提示进度, 下载过程中按钮不可点击,防止重复的下载,下载完毕后会进行Toast的提示显示, 并且回复按钮的可点击性,进度条也会清空,当然如果下载中途结束应用进程就会进行进度的保存, 下次下载同样的文件时就会从进度记录进行下载,节省流量和时间 应用需要的应用权限: 访问网络权限 <uses-permission android:name="android.permission.INTERNET"/&

使用IntentService给自己的Android应用写一个文件下载器。

接着上一篇的http://www.cnblogs.com/zhengxt/p/3657833.html,当我们想给自己的APP写一个文件下载器时,可以用重写IntentService来实现. 使用IntentService有几个好处,IntentService继承于Service,适合拿来处理一些耗时又不需要去管它的任务.把要执行的任务用Intent加入到队列中,IntentService会有一个工作线程来取出队列中的Intent来处理.需要实现抽象方法onHandleIntent方法来执行这些

mongoDB-----针对某个或多个文档只需要部分更新可使用原子的更新修改器

update() db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } ) db.collection.update( criteria, objNew, upsert, multi )    四个参数的说明如下: criteria: update的查询条件,类似sql update查询内

案例:文件下载器

服务器 参考代码如下: from socket import * import sys def get_file_content(file_name): """获取文件的内容""" try: with open(file_name, "rb") as f: content = f.read() return content except: print("没有下载的文件:%s" % file_name) de

Unity3d -- Collider(碰撞器与触发器)

(2d与3d的Collider可以相互存在,但是无法相互协作,如2d是无法检测3d的,反之,一样) 在目前掌握的情况分析,在Unity中参与碰撞的物体分2大块:1.发起碰撞的物体.2.接收碰撞的物体. 1. 发起碰撞物体有:Rigodbody , CharacterController . 2. 接收碰撞物体由:所有的Collider . 工作的原理为:发生碰撞的物体中必须要有“发起碰撞”的物体.否则,碰撞不响应. 比如:墙用BoxCollider ,所以墙与墙之间无反应. 比如:一个带有Rig

Android 设定横屏,禁止屏幕旋转,Activity重置 [更新视频播放器相关]

1. 设定屏幕方向 当指定了屏幕的方向后(非SCREEN_ORIENTATION_UNSPECIFIED),屏幕就不会自己主动的旋转了 有2中方式控制屏幕方向: 1.1 改动AndroidManifest.xml 在AndroidManifest.xml的activity中增加: 横屏: android:screenOrientation="landscape" 竖屏: android:screenOrientation="portrait" 1.2 setRequ

文件下载器

服务器 参考代码如下: from socket import * import sys def get_file_content(file_name): """获取文件的内容""" try: with open(file_name, "rb") as f: content = f.read() return content except: print("没有下载的文件:%s" % file_name) de

Download Shuttle Pro mac文件下载器使用指南

Download Shuttle Pro是适用于macOS的最强大的下载管理器和加速器.它将文件下载分为多个部分,与使用Web浏览器相比,可以提高整体下载速度.使用我们的Pro版本,您可以访问我们的新媒体提取浏览器,该浏览器可让您下载嵌入或链接在您扫描的网页上的任何文件(视频,音乐,档案等). Download Shuttle Pro mac下载地址:https://www.macjb.com/article/228408.html 首次启动和使用该应用程序:首次启动该应用程序时,会出现空白屏幕

Unity3D粒子系统碰撞器,让粒子碰撞到物体之后消失

经过测试学习,总结了关于怎么让粒子和物体发生碰撞和怎么让粒子在碰撞后消失的几点看法: 首先给大家看一下我的粒子系统的配置图: 关于碰撞检测的主要配置我们看图中的Collision: 第一项:因为是一个3D游戏,所以这里我选择的是World 第二项(Dampen):抑制(0~1),选这个为1时(完全抑制),碰撞之后,阻止了粒子,可以使碰撞的粒子消失 第三项(Bounce):反弹(0~2),选完这个之后,可以让产生碰撞的粒子以某个角度反弹出去 第三项(Lifetime Loss):生命周期损失(0~