344 lines
10 KiB
C#
344 lines
10 KiB
C#
|
|
/****************************************************************************
|
||
|
|
* 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<string> mSearchDirList = new List<string>();
|
||
|
|
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<string> 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<string> 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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|