UH3L6——下载资源对比文件

必备知识点

  • string字符串相关(C#核心)
  • FTP下载相关(Unity网络开发基础中)

目标

从Ftp服务器上下载在编辑模式时上传的资源对比文件,并解析该资源对比文件,获取所有AB包的名字,大小和MD5码

实现流程

  • 由于下载使用异步执行,因此下载资源对比方法DownLoadABCompareFile​是异步方法,需要在传入资源对比文件下载完毕后要执行的回调函数

  • Main​脚本的start​方法内

    1. 程序启动后调用ABUpdateManager​的DownLoadABCompareFile​方法,传入回调匿名函数
  • ABUpdateManager​的DownLoadABCompareFile​方法内

    1. 先声明下载是否完毕,最多重试次数以及下载路径的变量

    2. 进入循环下载流程,如果没有下载完毕且最多重试次数大于0时就下载资源对比文件,

    3. 创建Task​任务调用下载方法DownLoadFile​,传入文件名和下载路径

      • ABUpdateManager​的DownLoadFile​内

        1. 尝试执行下载流程,如果下载报错输出下载失败并返回false
        2. 传入的文件名和服务器地址拼接为下载地址,创建FTP连接请求
        3. 设置FTP连接请求通信凭证,代理设置为null​,请求完毕后关闭控制连接,操作命令设置为下载,指定传输二进制类型数据
        4. 通过FTP连接请求获取连接响应,通过连接响应获取下载流,创建本地文件流,从下载流下载数据到本地流,
        5. 下载完毕,关闭流,返回ture
    4. 等待DownLoadFile​执行完成,根据其返回值是否为true​决定是否下载完毕,如果下载完毕就会跳出循环,下载失败就最多重试次数减一

    5. 下载完毕或者连续下载失败导致最多重试次数归0,就结束方法,执行回调函数,传入下载是否完毕

  • Main​脚本的start​方法内传入的下载回调函数

    1. 如果传入false​,则说明下载失败,输出失败信息

    2. 如果传入ture​,则说明下载成功,执行资源对比文件的解析方法GetRemoteABCompareFileInfo

      • ABUpdateManager​的GetRemoteABCompareFileInfo​内

        1. 从下载路径读取资源对比文件,获取其中的字符串内容
        2. 通过'|'​来分割不同AB包消息,' '​分割同一AB包的不同消息,
        3. 每个AB包消息都有一个ABInfo​对象存储,ABInfo​对象内有文件名,大小,MD5码字段来存储一个AB包的数据
        4. 将所有的ABInfo​对象作为值存入到字典remoteInfo​内,以AB包文件名为键,为后面的下载AB包作准备
    3. 执行后面的下载AB包方法(下一章)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Main : MonoBehaviour
{
void Start()
{
print(Application.persistentDataPath);
ABUpdateManager.Instance.DownLoadABCompareFile((isOver) =>
//下载资源对比文件完毕后要执行的函数
{
if (isOver)
{
ABUpdateManager.Instance.GetRemoteABCompareFileInfo();
//TODO.. 下载AB包
}
else
print("下载失败,网络出现问题了");
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;

public class ABUpdateManager : MonoBehaviour
{
private static ABUpdateManager instance;
public static ABUpdateManager Instance
{
get
{
if (instance == null)
{
GameObject obj = new GameObject("ABUpdateManager");
instance = obj.AddComponent<ABUpdateManager>();
}
return instance;
}
}

//用于存储远端AB包消息的字典,之后和本地进行对比即可完成更新下载相关逻辑
private Dictionary<string, ABInfo> remoteInfo = new Dictionary<string, ABInfo>();

private void OnDestroy()
{
instance = null;
}

public async void DownLoadABCompareFile(UnityAction<bool> overCallBack)
{
//从资源服务器下载资源对比文件
bool isOver = false;
int reDownloadMaxNum = 5;
string path = Application.persistentDataPath + "/ABCompareInfo.txt";
while (!isOver && reDownloadMaxNum > 0)
{
await Task.Run(() =>
{
isOver = DownLoadFile("ABCompareInfo.txt", path);
});
--reDownloadMaxNum;
}
overCallBack?.Invoke(isOver);
}

/// <summary>
/// 获取下载下来的AB包中的消息
/// </summary>
public void GetRemoteABCompareFileInfo()
{
string info = File.ReadAllText(Application.persistentDataPath + "/ABCompareInfo.txt");
//通过分隔符把不同的AB包消息分割开来
string[] strs = info.Split('|');
string[] infos;
for (int i = 0; i < strs.Length; i++)
{
//通过空格将AB包不同的消息分割开来,实例化AB包消息类对象并加入到字典记录下来
infos = strs[i].Split(' ');
remoteInfo.Add(infos[0], new ABInfo(infos[0], infos[1], infos[2]));
}
Debug.Log("远端AB包对比文件,内容获取结束");
}

public bool DownLoadFile(string fileName, string localPath)
{
try
{
//创建一个FTP连接 用于下载
FtpWebRequest request = FtpWebRequest.Create(new Uri("ftp://192.168.1.102/AB/PC/" + fileName)) as FtpWebRequest;
//设置通信凭证 这样才能下载(如果有匿名账号,可以不设置凭证,但是实际开发中建议不要设置匿名账号)
NetworkCredential credential = new NetworkCredential("MrTang", "MrTang123");
request.Credentials = credential;
//其他设置:代理设置为null,请求完毕后关闭控制连接,操作命令设置为下载,指定传输二进制类型数据
request.Proxy = null;
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.UseBinary = true;
FtpWebResponse response = request.GetResponse() as FtpWebResponse;
Stream downLoadStream = response.GetResponseStream();
using (FileStream file = File.Create(localPath))
{
byte[] bytes = new byte[2048];
int contentLength = downLoadStream.Read(bytes, 0, bytes.Length);
while (contentLength > 0)
{
file.Write(bytes, 0, contentLength);
contentLength = downLoadStream.Read(bytes, 0, bytes.Length);
}
file.Close();
downLoadStream.Close();
}
return true;
}
catch (Exception e)
{
Debug.Log($"{fileName}下载失败:{e.Message}");
return false;
}
}

//AB包消息类
private class ABInfo
{
public string name; //AB包名字
public long size; //AB包大小
public string md5; //AB包MD5码

public ABInfo(string name, string size, string md5)
{
this.name = name;
this.size = long.Parse(size);
this.md5 = md5;
}
}
}