使用说明:

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. signalr推送消息

    参考:Tutorial: Getting Started with SignalR 2 and MVC 5 环境:vs2013,webapi2,entity framework6.0 实现效果:当用户 ...

  2. 物联网平台设计心得:DateTimePicker实现选择联动

    所谓的选择联动,就是指,当我DateTimePicker1选择2月4号的时候,我DateTimePicker2只能选择2月4号和2月5号两天,当然你可以自行规定要选择的日期.这在一些图表查询条件里面是 ...

  3. ajax返回值中有回车换行、空格的解决方法分享

    最近在写一个页面,用jquery ajax来实现判断,刚写好测试完全没有问题,过了两天发现出现问题,判断不成了.后来发现所有alert出来的返回值前面都会加若干换行和空格.(至今不明白,同一台电脑,同 ...

  4. iOS——学习网址收集+如何提高iOS开发技能

    1 一个比系统自带的终端好用的软件:http://www.iterm2.com 2 学习和遇到技术问题可以去的网站: CocoaChina      http://developer.cocoachi ...

  5. Writing Clean Code 读后感

    最近花了一些时间看了这本书,书名是 <Writing Clean Code ── Microsoft Techniques for Developing Bug-free C Programs& ...

  6. virtual memory exhausted: Cannot allocate memory

    ~$free total used free shared buffers cached Mem: 1017832 784328 233504 356 12844 14692 -/+ buffers/ ...

  7. 【USACO 2.4】The Tamworth Two

    题意:C代表cows,F代表farmer,一开始都向北,每分钟前进1步,如果前方不能走,则这分钟顺时针转90°,问多少步能相遇,或者是否不可能相遇,10*10的地图. 题解:dfs,记录状态,C和F的 ...

  8. ORB-SLAM(三)地图初始化

    单目SLAM地图初始化的目标是构建初始的三维点云.由于不能仅仅从单帧得到深度信息,因此需要从图像序列中选取两帧以上的图像,估计摄像机姿态并重建出初始的三维点云. ORB-SLAM中提到,地图初始化常见 ...

  9. 精通Web Analytics 2.0 (6) 第四章:点击流分析的奇妙世界:实际的解决方案

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第四章:点击流分析的奇妙世界:实际的解决方案 到开始实际工作的时候了.哦耶! 在本章中,您将了解到一些最重要的网络分析报告,我将 ...

  10. 【BZOJ-1340】Escape逃跑问题 最小割

    1340: [Baltic2007]Escape逃跑问题 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 264  Solved: 121[Submit] ...