使用说明:

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. SQL Left Join, Right Join, Inner Join, and Natural Join 各种Join小结

    在SQL语言中,存在着各种Join,有Left Join, Right Join, Inner Join, and Natural Join等,对于初学者来说肯定一头雾水,都是神马跟神马啊,它们之间到 ...

  2. 【swift学习笔记】三.使用xib自定义UITableViewCell

    使用xib自定义tableviewCell看一下效果图 1.自定义列 新建一个xib文件 carTblCell,拖放一个UITableViewCell,再拖放一个图片和一个文本框到tableviewc ...

  3. System.Diagnostics.Process 启动进程资源或调用外部的命令的使用

    经常看到一些程序在保存为一个txt,或者excel的文件的时候,保存完毕立即打开, 启动程序或打开文件的代码 System.Diagnostics.Process.Start(System.IO.Pa ...

  4. Spring Boot入门===Hello World

    昨天无意间看到Spring Boot ,今天又了解了一下,试着写一个Hello World!  今天看了半天,最后还是要用Maven最方便!以下: 一.工具 JDK1.7 Eclipse Maven ...

  5. servlet的四个作用域

    作用域规定的是变量的有效期限,servlet有四个作用域对象,这里只说三个: 一. request作用域: 1.作用范围: 就是指从http请求发起,到服务器处理结束,返回响应的整个过程.在这个过程中 ...

  6. canvas弹动

    弹动,和缓动类似,不过是在终点前反复运动几次达到反弹的效果,具体的算法就是用目标点(target)和物体(mouse)的距离乘以系数累加至坐标上,这样就会有简单的弹动效果,但是一般的弹动效果都是慢慢变 ...

  7. lvs/dr配置

    lvs/dr Director server : DIP:192.168.1.100/24  eth0 VIP:192.168.1.101/24  eth0:0 Real server: Real1: ...

  8. Spinner

    资源的方式添加 安卓中的下拉框 Spinner可以通过xml string中配置 <string-array name="spingarr"> <item> ...

  9. css-css权威指南学习笔记4

    第三章 1.继承的值没有特殊性,甚至连0的特殊性都没有.所以改变超链接的样式一般需要独立声明,无法通过继承改变. 2.层叠--冲突的声明通过这个层叠的过程排序,并由此确定最终的文档表示.这个过程的核心 ...

  10. BZOJ4614 [Wf2016]Oil

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...