public override void EnterState(Hashtable hash) { GameStateManager.Instance.GameStateChang(GameStates.CopyToPersistent); #if UNITY_EDITOR if (!AssetBundleManager.ResUpdateInEditor) { UnzipStreamingComplete(null); return; } #endif this.serverVersionConfig = (VersionConfig)hash["serverVersionConfig"]; versionVo = (FileUpdateVo)hash["versionVo"]; VersionConfig streamVersionConfig = (VersionConfig)hash["streamVersionConfig"]; TaskManager.Instance.StartCoroutine(LoadResVersion(versionVo, streamVersionConfig)); }
/// <summary> /// /// </summary> /// <param name="serverVersionConfig">如果不为空,则需要写入</param> /// <param name="checkResult">如果不为空,则需要删除文件或者下载文件</param> /// <param name="fileListBytes">下载之后的文本列表</param> /// <param name="url"></param> /// <param name="random"></param> /// <returns></returns> IEnumerator StartDownRes(VersionConfig serverVersionConfig, byte[] fileListBytes, List <FileUpdateVo> fileVoList, FileUpdateVo versionVo) { FileUpdateVo fileUpdateVo; string url = versionVo.Url; string random = versionVo.Random; float allSize = Util.SumSize(fileVoList, fileVoList.Count); for (int i = 0; i < fileVoList.Count; i++) { GameStateManager.Instance.DownProgressHandle(GameStates.DownResource, fileVoList, i, allSize); fileUpdateVo = fileVoList[i]; WWW www = new WWW(fileUpdateVo.FileUrl); yield return(www); if (string.IsNullOrEmpty(www.error)) { Util.WriteFile(fileUpdateVo.PersistentPath, www.bytes); } else { UDebug.LogError(string.Format("{0}down failed:{1}", fileUpdateVo.FileUrl, www.error)); yield break; } www.Dispose(); } if (fileListBytes != null) { fileUpdateVo = new FileUpdateVo(AppConst.FileListName, url, random, string.Empty, 0); Util.WriteFile(fileUpdateVo.PersistentPath, fileListBytes); } if (serverVersionConfig != null) { if (File.Exists(versionVo.PersistentPath)) { File.Delete(versionVo.PersistentPath); string json = JsonUtility.ToJson(serverVersionConfig); File.WriteAllText(versionVo.PersistentPath, json); } } GameStateManager.Instance.DownProgressHandle(GameStates.DownResource, fileVoList, fileVoList.Count, allSize); yield return(new WaitForEndOfFrame()); DownResourceComplete(); }
/// <summary> /// 打包初始包 /// </summary> public static void BuildInitial(string saPath) { //string saPath = ResourceConfig.SA_AB + ResourceConfig.Platform; FileHelper.CleanDirectory(saPath); if (!Directory.Exists(saPath)) { Directory.CreateDirectory(saPath); } VersionConfig versionProto = new VersionConfig(); using (FileStream fileStream = new FileStream($"{saPath}/Version.txt", FileMode.Create)) { byte[] bytes = JsonHelper.ToJson(versionProto).ToByteArray(); fileStream.Write(bytes, 0, bytes.Length); } }
private static void GenerateVersionInfo(string dir) { //将所有的AB文件写入到 FileInfoDict 这个字典中 VersionConfig versionProto = new VersionConfig(); GenerateVersionProto(dir, versionProto, ""); //创建一个文件流 然后往这个流里写入数据 using (FileStream fileStream = new FileStream($"{dir}/Version.txt", FileMode.Create)) { //序列化成byte[] byte[] bytes = JsonHelper.ToJson(versionProto).ToByteArray(); //通过字节数组写入到文本文件中 fileStream.Write(bytes, 0, bytes.Length); } }
private static void GenerateVersionProto(string dir, VersionConfig versionProto) { foreach (string file in Directory.GetFiles(dir)) { string md5 = MD5Helper.FileMD5(file); FileInfo fi = new FileInfo(file); long size = fi.Length; versionProto.FileInfoDict.Add(fi.Name, new FileVersionInfo { File = fi.Name, MD5 = md5, Size = size, }); } }
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ // Private Static Method // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ private static IEnumerable <(string, string)> GetAllPropertyAndValueTuples(TIniTarget target) { return(target.GetType().GetProperties() .Where(x => { var iniTargetAttr = (IniTargetAttribute)x.GetCustomAttribute(typeof(IniTargetAttribute), true); if (iniTargetAttr is null) { return false; } // サポート対象外の場合、出力対象に含めない return VersionConfig.IsGreaterVersion(iniTargetAttr.SupportMinVersion); }) .Select(propertyInfo => (propertyInfo.Name, (string)propertyInfo.GetValue(target)))); }
/// <summary> /// 打包初始包 /// </summary> public static void BuildInitial() { string saPath = "Assets/StreamingAssets"; if (!Directory.Exists(saPath)) { Directory.CreateDirectory(saPath); } VersionConfig versionProto = new VersionConfig(); using (FileStream fileStream = new FileStream($"{saPath}/Version.txt", FileMode.Create)) { byte[] bytes = JsonHelper.ToJson(versionProto).ToByteArray(); fileStream.Write(bytes, 0, bytes.Length); } }
static int GetFileListNeedDownloaded(IntPtr L) { try { ToLua.CheckArgsCount(L, 3); GameUpdater obj = (GameUpdater)ToLua.CheckObject(L, 1, typeof(GameUpdater)); VersionConfig arg0 = (VersionConfig)ToLua.CheckObject(L, 2, typeof(VersionConfig)); VersionConfig arg1 = (VersionConfig)ToLua.CheckObject(L, 3, typeof(VersionConfig)); System.Collections.Generic.List <string> o = obj.GetFileListNeedDownloaded(arg0, arg1); ToLua.PushObject(L, o); return(1); } catch (Exception e) { return(LuaDLL.toluaL_exception(L, e)); } }
/// <summary> /// 生成版本配置 /// </summary> /// <param name="path">路径</param> /// <param name="version">版本号</param> /// <returns></returns> /// <summary> /// 解析版本配置信息 /// </summary> /// <param name="content"></param> /// <returns></returns> public static VersionConfig ReadVersionConfig(string content) { VersionConfig vc = new VersionConfig(); XmlDocument doc = new XmlDocument(); doc.LoadXml(content); XmlElement root = null; root = doc.DocumentElement; XmlElement version = root.GetElementsByTagName("Version").Item(0) as XmlElement; string sVersion = version.InnerText; int.TryParse(sVersion, out vc.version); XmlElement files = root.GetElementsByTagName("Files").Item(0) as XmlElement; XmlNodeList fileList = files.GetElementsByTagName("File"); for (int i = 0; i < fileList.Count; ++i) { XmlElement file = fileList.Item(i) as XmlElement; XmlElement path = file.GetElementsByTagName("Path").Item(0) as XmlElement; string sPath = path.InnerText; XmlElement md5 = file.GetElementsByTagName("MD5").Item(0) as XmlElement; string sMD5 = md5.InnerText; XmlElement sizeByte = file.GetElementsByTagName("SizeByte").Item(0) as XmlElement; int iSizeByte = Int32.Parse(sizeByte.InnerText); VersionFileConfig vfc = new VersionFileConfig(); vfc.path = sPath; vfc.md5 = sMD5; vfc.sizeByte = iSizeByte; if (vc.fileDict.ContainsKey(vfc.path)) { vc.fileDict.Remove(vfc.path); } vc.fileDict.Add(vfc.path, vfc); } return(vc); }
private HandleServerHelloState( IServiceProvider serviceProvider, VersionConfig versionConfig, CipherSuiteConfig cipherSuiteConfig, RandomConfig randomConfig, SessionConfig sessionConfig, ServerHelloMessage handshake) { _serviceProvider = serviceProvider; _versionConfig = versionConfig; _cipherSuiteConfig = cipherSuiteConfig; _randomConfig = randomConfig; _sessionConfig = sessionConfig; _handshake = handshake; }
public static VersionConfig ReadVersion(string path) { VersionConfig version = new VersionConfig(); if (File.Exists(path)) { StreamReader sr = new StreamReader(path); string content = sr.ReadToEnd(); sr.Close(); version = JsonFx.Json.JsonReader.Deserialize <VersionConfig>(content); } else { Debug.LogError("目标路径没有版本文件: " + path); } return(version); }
/// <summary> /// 初始化本地版本 /// </summary> IEnumerator InitVersion() { var localVersionConfigPath = PathUtil.GetLocalFilePath(VERSIONCONFIGFILE, true); var www = new WWW(localVersionConfigPath); yield return(www); mLocalVersionConfig = JsonUtility.FromJson <VersionConfig>(www.text); www.Dispose(); var serverVersionConfigPath = PathUtil.GetServerFileURL(VERSIONCONFIGFILE); www = new WWW(serverVersionConfigPath); yield return(www); mServerVersionConfig = string.IsNullOrEmpty(www.error) ? JsonUtility.FromJson <VersionConfig>(www.text) : mLocalVersionConfig; www.Dispose(); }
public void StopUpdate() { WWWManager.Instance.StopAllWWW(); NewCfg = null; OldCfg = null; files = null; totalDownloaded = 0; currentDownloaded = 0; WWWManager.OnStartDownload -= OnUpdateDownloadStart; WWWManager.OnEndDownload -= OnUpdateDownloadEnd; WWWManager.OnDownloading -= OnUpdateDownloading; WWWManager.OnDownloadError -= OnUpdateDownloadError; }
static int CheckVersionNumber(IntPtr L) { try { ToLua.CheckArgsCount(L, 3); GameUpdater obj = (GameUpdater)ToLua.CheckObject(L, 1, typeof(GameUpdater)); VersionConfig arg0 = (VersionConfig)ToLua.CheckObject(L, 2, typeof(VersionConfig)); VersionConfig arg1 = (VersionConfig)ToLua.CheckObject(L, 3, typeof(VersionConfig)); bool o = obj.CheckVersionNumber(arg0, arg1); LuaDLL.lua_pushboolean(L, o); return(1); } catch (Exception e) { return(LuaDLL.toluaL_exception(L, e)); } }
private async Task LoadVersionConfig() { #if NETFX_CORE var configData = await taggerWebView.InvokeScriptAsync("eval", new[] { "if (typeof mps !== 'undefined') { JSON.stringify(mps); }" }); #elif WINDOWS_PHONE var configData = taggerWebView.InvokeScript("eval", new[] { "if (typeof mps !== 'undefined') { JSON.stringify(mps); }" }); #endif if (configData != null && !string.IsNullOrWhiteSpace(configData.ToString())) { config = VersionConfig.Parse(configData.ToString()); } else { config = VersionConfig.Default; } requestQueue.ResetQueueSize(config.OfflineDispatchLimit, config.DispatchExpiration); }
IEnumerator LoadResVersion(FileUpdateVo vo, VersionConfig streamVersionConfig) { bool isExists = File.Exists(vo.PersistentPath); bool needCopy = !isExists; VersionConfig persistentAssetsConfig = null; if (isExists) { string persistentStr = File.ReadAllText(vo.PersistentPath); if (GameStateManager.Instance.showGameStateLog) { UDebug.Log("persistentStr " + persistentStr); } persistentAssetsConfig = JsonUtility.FromJson <VersionConfig>(persistentStr); if (persistentAssetsConfig.packageVersion != streamVersionConfig.packageVersion) { needCopy = true; } } if (needCopy) { string resRoot = PathHelper.PersistentPath + "/" + AppConst.ResRoot; if (Directory.Exists(resRoot)) { Directory.Delete(resRoot, true); } } if (!needCopy) { if (GameStateManager.Instance.showGameStateLog) { UDebug.Log("不需要解压文件"); } UnzipStreamingComplete(persistentAssetsConfig); yield break;; } else { TaskManager.Instance.StartCoroutine(OnExtractResource(vo.Url, vo.Random, streamVersionConfig)); } }
/// <summary> /// 返回是否需要下载 /// </summary> /// <returns></returns> public async Task <bool> LoadInfo() { UnityWebRequestAsync webRequestAsync = MonoBehaviourHelper.CreateTempComponent <UnityWebRequestAsync>(); string remoteVersionText = string.Empty; try { //下载remote version.txt string versionUrl = LoadBundlePathRoot() + "StreamingAssets/Version.txt"; await webRequestAsync.DownloadAsync(versionUrl); remoteVersionText = webRequestAsync.Request.downloadHandler.text; } catch (Exception e) { if (e.Message.Contains("request error")) { webRequestAsync.Dispose(); Debug.Log($"load VersionText error:'{e.Message}'"); StaticData.isUseStreamingAssetRes = true; OnFileServerNotReach(e.Message); return(false); } } finally { Destroy(webRequestAsync.gameObject); } Debug.Log($"remoteVersionText:{remoteVersionText}"); if (!remoteVersionText.StartsWith("{")) { Debug.Log("remote version text is not a correct json"); this.remoteVersionConfig = null; return(false); } this.remoteVersionConfig = JsonHelper.FromJson <VersionConfig>(remoteVersionText); var needDown = await AnalyseVersionConfig(); if (needDown == false) { return(false); } return(true); }
/// <summary> /// 比较remoteVersionConfig和localVersionConfig,删除服务器端没有的本地ab,分析需要下载的bundle /// </summary> /// <returns></returns> private async Task <bool> AnalyseVersionConfig() { bool isNeedDown = true; VersionConfig localVersionConfig = await GetLocalVersionConfig(); if (localVersionConfig != null) { foreach (FileVersionInfo fileVersionInfo in localVersionConfig.FileInfoDict.Values) { if (this.remoteVersionConfig.FileInfoDict.ContainsKey(fileVersionInfo.File)) { continue; } string abPath = Path.Combine(PathHelper.AppHotfixResPath, fileVersionInfo.File); if (File.Exists(abPath)) { File.Delete(abPath); } } } foreach (FileVersionInfo remoteFileVersionInfo in this.remoteVersionConfig.FileInfoDict.Values) { if (localVersionConfig != null && localVersionConfig.FileInfoDict.TryGetValue(remoteFileVersionInfo.File, out FileVersionInfo localFileVersionInfo)) { if (remoteFileVersionInfo.MD5 == localFileVersionInfo.MD5) { continue; } } if (remoteFileVersionInfo.File == "Version.txt") { continue; } this.needDownLoadBundles.Enqueue(remoteFileVersionInfo.File); this.TotalSize += remoteFileVersionInfo.Size; } DownloadInfo.TotalSize = TotalSize; if (DownloadInfo.TotalSize <= 0) { isNeedDown = false; } return(isNeedDown); }
IEnumerator LoadSobj() { WWW www = new WWW("file://" + Application.dataPath + "/ABs/version.assetbundle"); yield return(www); //转换资源为VersionConfig,这个sd对象将拥有原来在编辑器中设置的数据。 VersionConfig sd = www.assetBundle.mainAsset as VersionConfig; VersionConfig vc = www.assetBundle.LoadAsset <VersionConfig>("version"); if (sd != null) { print(sd.version); } if (vc != null) { print(vc.version); } }
public HandleServerHelloDoneState( IServiceProvider serviceProvider, ICipherSuitesProvider cipherSuitesProvider, Connection connection, HandshakeWriter writer, HandshakeFinishedService handshakeFinishedService, CipherSuiteConfig cipherSuiteConfig, VersionConfig versionConfig) { _serviceProvider = serviceProvider; _cipherSuitesProvider = cipherSuitesProvider; _connection = connection; _writer = writer; _handshakeFinishedService = handshakeFinishedService; _cipherSuiteConfig = cipherSuiteConfig; _versionConfig = versionConfig; }
public SendingServerHelloState( IServiceProvider serviceProvider, ICipherSuitesProvider cipherSuitesProvider, HandshakeWriter writer, VersionConfig versionConfig, RandomConfig randomConfig, SessionConfig sessionConfig, CipherSuiteConfig cipherSuiteConfig) { _serviceProvider = serviceProvider; _cipherSuitesProvider = cipherSuitesProvider; _writer = writer; _versionConfig = versionConfig; _randomConfig = randomConfig; _sessionConfig = sessionConfig; _cipherSuiteConfig = cipherSuiteConfig; }
IEnumerator Co_Launch() { if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) { if (AssetsCopyTask.copiedVersion != VersionConfig.Get().version) { var assetCopy = AssetsCopyTask.BeginCopy(VersionConfig.Get().version); while (!assetCopy.done) { yield return(null); } } } ConfigInitiator.Init(); yield return(new WaitForSeconds(1f)); SceneLoad.Instance.LoadLogin(); }
private void CheckResourceComplete(VersionConfig serverVersionConfig, FileCheckResult checkResult, byte[] fileListBytes, FileUpdateVo versionVo) { Hashtable hash = new Hashtable(); hash["checkResult"] = checkResult; hash["serverVersionConfig"] = serverVersionConfig; hash["fileListBytes"] = fileListBytes; hash["versionVo"] = versionVo; if (checkResult != null) //&& checkResult.downSize > 1000)//大于某个值了才提示 { //弹窗,确认之后才能继续更新 GameStateManager.Instance.ShowPop(true, string.Format("有{0}b资源更新,点击确定开始更新!", checkResult.downSize), () => { this.stateMachine.SetState <State_DownResource>(hash); }, GameStateManager.Instance.Quit); } else { this.stateMachine.SetState <State_DownResource>(hash); } }
/// <summary> /// 写版本配置 /// </summary> /// <param name="vc"></param> /// <returns></returns> public static void WriteVersionConfig(VersionConfig vc) { var versionFile = new System.IO.StreamWriter(PathUtil.GetFullPath(PathUtil.GetRelativePathToDataPath(PathConfig.version)), false, Encoding.UTF8); StringBuilder sb = new StringBuilder(); versionFile.WriteLine("<Config>"); versionFile.Write("\t<Version>"); versionFile.Write(vc.version.ToString()); versionFile.WriteLine("</Version>"); versionFile.WriteLine("\t<Files>"); foreach (KeyValuePair <string, VersionFileConfig> kv in vc.fileDict) { VersionFileConfig vfc = kv.Value; versionFile.WriteLine("\t\t<File>"); versionFile.Write("\t\t\t<Path>"); versionFile.Write(vfc.path.ToLower()); versionFile.WriteLine("</Path>"); versionFile.Write("\t\t\t<MD5>"); versionFile.Write(vfc.md5); versionFile.WriteLine("</MD5>"); versionFile.Write("\t\t\t<SizeByte>"); versionFile.Write(vfc.sizeByte); versionFile.WriteLine("</SizeByte>"); versionFile.WriteLine("\t\t</File>"); } versionFile.WriteLine("\t</Files>"); versionFile.WriteLine("</Config>"); versionFile.Flush(); versionFile.Close(); }
private static void GenerateVersionProto(string dir, VersionConfig versionProto, string relativePath, bool pIsAbSec) { foreach (string file in Directory.GetFiles(dir)) { string md5 = MD5Helper.FileMD5(file); FileInfo fi = new FileInfo(file); long size = fi.Length; string filePath = relativePath == "" ? fi.Name : $"{relativePath}/{fi.Name}"; versionProto.FileInfoDict.Add(filePath, new FileVersionInfo { File = filePath, MD5 = md5, Size = size, }); } foreach (string directory in Directory.GetDirectories(dir)) { DirectoryInfo dinfo = new DirectoryInfo(directory); string rel = relativePath == "" ? dinfo.Name : $"{relativePath}/{dinfo.Name}"; GenerateVersionProto($"{dir}/{dinfo.Name}", versionProto, rel, pIsAbSec); } string tDayHour = DateTime.Now.ToString("yyMMddHHmm"); versionProto.Version = int.Parse(tDayHour); versionProto.ABSecurity = pIsAbSec ? 2 : 1;//0未知,去load下, 1不使用加密 ,2加密-------若0使用不加密 #region MyRegion //try //{//加密时,把version.txt删除了,无法记录第几次,只能使用时间记录了 // var oldConfig = JsonHelper.FromJson<VersionConfig>(File.ReadAllText($"{dir}/Version.txt")); // var oldver = oldConfig.Version.ToString().Substring(6, 4); // versionProto.Version = int.Parse(tDay + oldver) + 1; //} //catch (Exception) //{ // versionProto.Version = int.Parse(tDay + "1000"); //} #endregion }
/// <summary> /// 获取文件需要下载的文件列表 /// </summary> /// <returns></returns> public List <string> GetFileListNeedDownloaded(VersionConfig oldCfg, VersionConfig newCfg) { Dictionary <string, VersionFileConfig> oldDict = oldCfg.fileDict; Dictionary <string, VersionFileConfig> newDict = newCfg.fileDict; List <string> files = new List <string>(); foreach (KeyValuePair <string, VersionFileConfig> kv in newDict) { if (oldDict.ContainsKey(kv.Key)) { VersionFileConfig oldVfc = oldDict[kv.Key]; VersionFileConfig newVfc = kv.Value; if (oldVfc.md5 != newVfc.md5) { files.Add(kv.Key); } oldDict.Remove(kv.Key); } else { files.Add(kv.Key); } } foreach (KeyValuePair <string, VersionFileConfig> kv in oldDict) { string path = PathUtil.GetPersistentDataPath(kv.Key); if (PathUtil.ExistsFile(path)) { File.Delete(path); } } return(files); }
// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ // Private Static Method // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ /// <summary> /// バージョンによる定義チェックを行い、警告メッセージを出力する /// </summary> /// <param name="value">変数アドレス値</param> private static void VersionCheck(int value) { var infoCode = value % 10; if (VersionConfig.IsUnderVersion(WoditorVersion.Ver2_01)) { // 「イベントの座標」のうち、10の位が5または6のアドレスは // ウディタVer2.01未満では非対応 if (infoCode == 5 || infoCode == 6) { WodiLibLogger.GetInstance().Warning(VersionWarningMessage.NotUnderInVariableAddress( value, VersionConfig.GetConfigWoditorVersion(), WoditorVersion.Ver2_01)); } } if (infoCode == 7 || infoCode == 8) { WodiLibLogger.GetInstance().Warning(VersionWarningMessage.NotUsingVariableAddress(value)); } }
private List <FileUpdateVo> PrepareDownRes(VersionConfig serverVersionConfig, FileCheckResult checkResult, byte[] fileListBytes, FileUpdateVo versionVo) { string url = versionVo.Url; string random = versionVo.Random; FileUpdateVo fileUpdateVo; string persistentMd5 = null; foreach (FileCheckInfo item in checkResult.DeleteList) { fileUpdateVo = new FileUpdateVo(item.name, url, random, item.md5, item.size); if (File.Exists(fileUpdateVo.PersistentPath)) { File.Delete(fileUpdateVo.PersistentPath); } } List <FileUpdateVo> fileVoList = new List <FileUpdateVo>(); for (int i = 0; i < checkResult.DownList.Count; i++) { FileCheckInfo item = checkResult.DownList[i]; fileUpdateVo = new FileUpdateVo(item.name, url, random, item.md5, item.size); if (File.Exists(fileUpdateVo.PersistentPath)) { persistentMd5 = Util.Md5file(fileUpdateVo.PersistentPath); } else { persistentMd5 = string.Empty; } if (persistentMd5 != fileUpdateVo.Md5)//需要下载 { fileVoList.Add(fileUpdateVo); } } return(fileVoList); }
public void CreateVersionFile(List <BundleInfo> bundles, bool copyToStreamingAssets = false) { string destPath = copyToStreamingAssets ? Config.resourcesPath + "/" + Config.bundleRelativePath : "AssetBundles/" + Config.platform + "/" + Config.bundleRelativePath; VersionConfig vc = new VersionConfig(); vc.versionNum = DateTime.Now.ToString(); vc.bundleRelativePath = Config.bundleRelativePath; // vc.bundles = bundles; foreach (var item in bundles) { if (!item.isExist() || copyToStreamingAssets) { vc.bundles.Add(item); } } string verJson = JsonMapper.ToJson(vc); // File.WriteAllText (destPath + "/" + Config.versionFileName + Config.suffix, verJson); }
private static void GenerateVersionProto(string dir, VersionConfig versionProto) { foreach (string file in Directory.GetFiles(dir)) { LogUtil.Log(file); if (file.EndsWith(".manifest")) { continue; } string md5 = FileMD5(file); System.IO.FileInfo fi = new System.IO.FileInfo(file); long length = fi.Length; versionProto.FileVersionInfos.Add(new FileVersionInfo { File = fi.Name, MD5 = md5, Size = (int)length, }); } }