/**************************************************************************** * Copyright (c) 2017 snowcold * Copyright (c) 2017 ~ 2020.10 liangxie * * https://qframework.cn * https://github.com/liangxiegame/QFramework * https://gitee.com/liangxiegame/QFramework * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ****************************************************************************/ using System.Collections.Generic; using System.IO; using ICSharpCode.SharpZipLib.Zip; using UnityEngine; namespace QFramework { public class ZipFileHelper : IZipFileHelper { private List mSearchDirList = new List(); private string mStreamingAssetsPath; private ZipFile mZipFile = null; public ZipFile GetZipFile() { return mZipFile; } public ZipFileHelper() { mSearchDirList.Add(AssetBundlePathHelper.PersistentDataPath4Res); mStreamingAssetsPath = AssetBundlePathHelper.StreamingAssetsPath; #if (UNITY_ANDROID) && !UNITY_EDITOR if (mZipFile == null) { mZipFile = new ZipFile(File.Open(UnityEngine.Application.dataPath, FileMode.Open, FileAccess.Read)); } #endif } ~ZipFileHelper() { #if UNITY_ANDROID && !UNITY_EDITOR if (mZipFile != null) { mZipFile.Close(); mZipFile = null; } #endif } public void InitStreamingAssetPath() { mStreamingAssetsPath = AssetBundlePathHelper.StreamingAssetsPath; } //在包内查找是否有改资源 private bool FindResInAppInternal(string fileRelativePath) { #if UNITY_IPHONE && !UNITY_EDITOR string absoluteFilePath = FindFilePathInternal(fileRelativePath); return !string.IsNullOrEmpty(absoluteFilePath); #elif UNITY_ANDROID && !UNITY_EDITOR int entryIndex = mZipFile.FindEntry(string.Format("assets/{0}", fileRelativePath), false); return entryIndex != -1; #else string absoluteFilePath = string.Format("{0}{1}", mStreamingAssetsPath, fileRelativePath); return File.Exists(absoluteFilePath); #endif } private void AddSearchPath(string dir) { mSearchDirList.Add(dir); } public bool FileExists(string fileRelativePath) { #if UNITY_IPHONE && !UNITY_EDITOR string absoluteFilePath = FindFilePath(fileRelativePath); return (!string.IsNullOrEmpty(absoluteFilePath) && File.Exists(absoluteFilePath)); #elif UNITY_ANDROID && !UNITY_EDITOR string absoluteFilePath = FindFilePathInExteral(fileRelativePath); //先到外存去找 if (!string.IsNullOrEmpty(absoluteFilePath)) { return File.Exists(absoluteFilePath); } else { if (mZipFile == null) { return false; } return mZipFile.FindEntry(string.Format("assets/{0}", fileRelativePath), true) >= 0; } #else string filePathStandalone = string.Format("{0}{1}", mStreamingAssetsPath, fileRelativePath); return (!string.IsNullOrEmpty(filePathStandalone) && File.Exists(filePathStandalone)); #endif } public Stream OpenReadStream(string absFilePath) { if (string.IsNullOrEmpty(absFilePath)) { return null; } #if UNITY_ANDROID && !UNITY_EDITOR //Android 包内 if (absFilePath.Contains(".apk/")) { return OpenStreamInZip(absFilePath); } #endif FileInfo fileInfo = new FileInfo(absFilePath); if (!fileInfo.Exists) { return null; } return fileInfo.OpenRead(); } public void GetFileInInner(string fileName, List outResult) { #if UNITY_ANDROID && !UNITY_EDITOR //Android 包内 GetFileInZip(mZipFile, fileName, outResult); return; #endif AssetBundlePathHelper.GetFileInFolder(AssetBundlePathHelper.StreamingAssetsPath, fileName, outResult); } public byte[] ReadSync(string fileRelativePath) { string absoluteFilePath = FindFilePathInExteral(fileRelativePath); if (!string.IsNullOrEmpty(absoluteFilePath)) { return ReadSyncExtenal(fileRelativePath); } return ReadSyncInternal(fileRelativePath); } public byte[] ReadSyncByAbsoluteFilePath(string absoluteFilePath) { if (File.Exists(absoluteFilePath)) { FileInfo fileInfo = new FileInfo(absoluteFilePath); return ReadFile(fileInfo); } else { return null; } } private byte[] ReadSyncExtenal(string fileRelativePath) { string absoluteFilePath = FindFilePathInExteral(fileRelativePath); if (!string.IsNullOrEmpty(absoluteFilePath)) { FileInfo fileInfo = new FileInfo(absoluteFilePath); return ReadFile(fileInfo); } return null; } private byte[] ReadSyncInternal(string fileRelativePath) { #if UNITY_ANDROID && !UNITY_EDITOR return ReadDataInAndriodApk(fileRelativePath); #else string absoluteFilePath = FindFilePathInternal(fileRelativePath); if (!string.IsNullOrEmpty(absoluteFilePath)) { FileInfo fileInfo = new FileInfo(absoluteFilePath); return ReadFile(fileInfo); } #endif return null; } private byte[] ReadFile(FileInfo fileInfo) { using (FileStream fileStream = fileInfo.OpenRead()) { byte[] byteData = new byte[fileStream.Length]; fileStream.Read(byteData, 0, byteData.Length); return byteData; } } private string FindFilePathInExteral(string file) { string filePath; for (int i = 0; i < mSearchDirList.Count; ++i) { filePath = string.Format("{0}/{1}", mSearchDirList[i], file); if (File.Exists(filePath)) { return filePath; } } return string.Empty; } private string FindFilePath(string file) { // 先到搜索列表里找 string filePath = FindFilePathInExteral(file); if (!string.IsNullOrEmpty(filePath)) { return filePath; } // 在包内找 filePath = FindFilePathInternal(file); if (!string.IsNullOrEmpty(filePath)) { return filePath; } return null; } private string FindFilePathInternal(string file) { string filePath = string.Format("{0}{1}", mStreamingAssetsPath, file); if (File.Exists(filePath)) { return filePath; } return null; } private Stream OpenStreamInZip(string absPath) { string tag = "!/assets/"; string androidFolder = absPath.Substring(0, absPath.IndexOf(tag)); int startIndex = androidFolder.Length + tag.Length; string relativePath = absPath.Substring(startIndex, absPath.Length - startIndex); ZipEntry zipEntry = mZipFile.GetEntry(string.Format("assets/{0}", relativePath)); if (zipEntry != null) { return mZipFile.GetInputStream(zipEntry); } else { Debug.LogError($"Can't Find File {absPath}"); } return null; } public void GetFileInZip(ZipFile zipFile, string fileName, List outResult) { int totalCount = 0; foreach (var entry in zipFile) { ++totalCount; ICSharpCode.SharpZipLib.Zip.ZipEntry e = entry as ICSharpCode.SharpZipLib.Zip.ZipEntry; if (e != null) { if (e.IsFile) { if (e.Name.EndsWith(fileName)) { outResult.Add(zipFile.Name + "/!/" + e.Name); } } } } } private byte[] ReadDataInAndriodApk(string fileRelativePath) { byte[] byteData = null; //Log.I("Read From In App..."); if (mZipFile == null) { Debug.LogError("can't open apk"); return null; } //Log.I("Begin Open Zip..."); ZipEntry zipEntry = mZipFile.GetEntry(string.Format("assets/{0}", fileRelativePath)); //Log.I("End Open Zip..."); if (zipEntry != null) { //Log.I("Begin Read Zip..."); var stream = mZipFile.GetInputStream(zipEntry); byteData = new byte[zipEntry.Size]; //Log.I("Read Zip Length:" + byteData.Length); stream.Read(byteData, 0, byteData.Length); stream.Close(); } else { Debug.LogError(string.Format("Can't Find File {0}", fileRelativePath)); } return byteData; } } }