使用说明:

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 ( == val.Length)
{
PartialUrl = val[];
RelativePath = val[];
}
else if ( == val.Length)
{
PartialUrl = val[];
RelativePath = val[];
}
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 = ; //当前已下载的bundle个数
private int mBundleCount = ; //开始下载
public void Download(string url,string dir)
{
mBundleCount = ;
mTotalBundleCount = ;
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 = ; i < list.Count; i++)
{
var info = new PatchFileInfo(list[i]); if (!CheckNeedDownload(info))
{
continue;
} fileList.Add(info);
} mTotalBundleCount = fileList.Count; //开始下载所有文件
for (int i = ; 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, , 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=;i<list.Length-;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);
}
}
}
}

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

  1. Atitit 热更新资源管理器 自动更新管理器 功能设计

    Atitit 热更新资源管理器 自动更新管理器 功能设计 · 多线程并行下载支持 · 两层进度统计信息:文件级以及字节级 · Zip压缩文件支持 · 断点续传 · 详细的错误报告 · 文件下载失败重试 ...

  2. tcp案例之文件下载器

    文件下载器客户端 import socket def main(): # 1.创建一个tcp socket tcp_client_socket=socket.socket(socket.AF_INET ...

  3. python实现tcp文件下载器

    服务器端代码 import socket import os import threading # 处理客户端请求下载文件的操作(从主线程提出来的代码) def deal_client_request ...

  4. 使用网络TCP搭建一个简单文件下载器

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 目录 一丶项目介绍 二丶服务器Server 三丶测试TCP server服务器 四丶客户端Client 五丶测试客户端向服务器下载 ...

  5. {每日一题}:tcp协议实现简单的文件下载器(单任务版)

    文件下载器客户端 这个版本的只是为了方便回顾一下TCP客服端,服务端的创建流程,缺点就是  服务器一次只能让一个人访问下载,过两个写个使用面向对象写一个多线程版的强化一下. from socket i ...

  6. QT--HTTP文件下载器

    QT--HTTP文件下载器 1.pro文件添加 QT       += core gui network 2.头文件 #include <QNetworkAccessManager> #i ...

  7. Unity3D --对撞机/碰撞器 介绍

    碰撞器一般都用作触发器而用,刚体一般用作真实碰撞. 静态对撞机:一个对象有对撞机组件,没有刚体组件. 这种情况在场景中的静态物体应用较多,比如墙体,房屋等静止不动的物体. 物理引擎假设静态对撞机是不会 ...

  8. warensoft unity3d 更新说明

    warensoft unity3d 组件的Alpha版本已经发布了将近一年,很多网友发送了改进的Email,感谢大家的支持. Warensoft Unity3D组件将继续更新,将改进的功能如下: 1. ...

  9. Unity3D合并着色器

    unity 3d倒每次模型更多的是一种着色器.我可以拥有这些车型共享的地图想分享一个着色器.所以每次删除,然后附加,很麻烦.如何才能合并这些着色器? 采纳TexturePacking对 1.遍历gam ...

随机推荐

  1. javascript马赛克遮罩图片切换效果:XMosaic.js(转)

    新鲜出炉的javascript图片切换特效,实现的是马赛克遮罩切换.在flash里,好实现遮罩动画很简单,不过JS实现起来就有些困难了. XMosaic.js,与XScroll.js和XScroll2 ...

  2. C#软件设计——小话设计模式原则之:依赖倒置原则DIP

    前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做“全战”, ...

  3. shell中测试命变量是否已经定义

    (1)sehll实例 # cat subshell #!/bin/bash if (set -u; : $var); then #冒号与$间有空格 echo "Variable is set ...

  4. 【USACO 3.1】Contact(01子串按出现次数排序)

    题意:给你一个01字符串,将长度为a到b之间(包含a.b)的子串按照出现次数排序.注意输入输出格式 题解:01子串对应一个二进制,为了区别11和011这样的不同子串,我们把长度也记录下来,官方题解是在 ...

  5. evil program

    写的一个恶作剧程序,运行后直接重装系统吧,学习交流使用,后果自负. #include <windows.h> #pragma comment( linker, "/subsyst ...

  6. phpexcel导入数据部分数据有误

    数据在excel中是这样的: 插入数据库后是这样的: 很难发现,出错的那几条数据中的单元格中都有英文','符号,而phpexcel又是以','来拼接读取到的数据的. 解决办法:修改代码中的','为不常 ...

  7. bzoj 1004 Cards

    1004: [HNOI2008]Cards Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有 多少种染色方案,Sun ...

  8. 如何学习Oracle

    如何学习Oracle?分清几个概念是关键     经常有一些Oracle的初学者问到以下几个问题,这里集中解答一下,希望对大家有帮助.   1.如果有一定的数据库基础,知道SQL是怎么回事,即使写不出 ...

  9. WPF面试准备

    1.wpf中有两类模板,控件模板controltemplate和datatemplate都派生自Frameworktemplate. 总共有三大模板 ControlTemplate,ItemsPane ...

  10. 11月10日下午 ajax做显示信息以后用ajax、Bootstrp做弹窗显示信息详情

    1.用ajax做弹窗显示信息详情 nation.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&qu ...