使用说明:

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. 【.NET实战教程】北风网基于ASP.NET多层架构下的企业级进销存软件全程培训

    .Net进销存系统详细课程大纲(开发工具采用VS2008+sqlsever2005) [小编提醒:现在学习的话,可以使用vs2012+sql 2008 学习的是思路,教学环境不一定要一模一样]1.项目 ...

  2. javascript 中断函数的使用 setInterval()——返回顶部

    方法名称:gotop() 功能描述:点击某个元素,调用方法gotop(),固定间隔,滚动至屏幕顶部 日期 :2016.06.06 16:02 author  :cyh2009@live.com < ...

  3. 简单所以不要忽视,关于\r\n和\n程序员应了解的实际应用

    众所周知,\r叫回车符,\n叫换行符. 由于历史原因,windows环境下的换行符是\r\n;(文章最后会稍微解释这个历史原因) linux和html等开源或公开标准中的换行符是\n. 记录这篇笔记的 ...

  4. 理解C# 4 dynamic(2) – ExpandoObject的使用

    ExpandoObject的使用非常简单,很容易入手.上一篇里面已经有详细的介绍了,可以看这里(理解C# 4 dynamic(1) - var, object, dynamic的区别以及dynamic ...

  5. 用VS开发PHP扩展

    开发前准备工作: VS(我用的2013) Cygwin(下载地址:http://www.cygwin.com/) 搭载了php运行环境的IIS7.5 (用来测试) php编译后的程序和编译前的源码,我 ...

  6. raw_input和input的区别

    raw_input的返回类型是String类型 input的返回类型是int类型 >>> rawinput = raw_input("raw_input:") r ...

  7. javascript闭包理解

    //闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...

  8. 中软培训第一周复习总结 --简单的HTML 与CSS

    一些需要记住的点: day1 HTML格式及简单标签: html 文件一般格式: 1 <html> 2 <head lang="en"> 3 <met ...

  9. SpringMVC常用注解的用法

    1. @PathVariable 当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvari ...

  10. 【Beta】Scrum03

    Info 时间:2016.12.01 21:30 时长:15min 地点:大运村1号公寓5楼楼道 类型:日常Scrum会议 NXT:2016.12.04 21:30 Task Report Name ...