最近研究了一下使用U3D解压压缩包,需要引入ICSharpCode.SharpZipLib.dll,稍后会添加下载链接。
方法一:
本示例是在打开PC端的.zip文件,因为是在本地的文件,所以没有下载代码,但是添加了一个解压进度条,下面直接贴代码:
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using UnityEngine.UI;
public class ZipUtility : MonoBehaviour
{
[SerializeField] private Slider slider;
[SerializeField] private Text sliderText;
[SerializeField] private string zipPath;
[SerializeField] private string outPath;
/// <summary>
/// 解压缩按钮
/// </summary>
[SerializeField] private Button UnZipBtn;
// Use this for initialization
void Start()
{
UnZipBtn.onClick.AddListener(UnZip);
}
/// <summary>
/// 解压Zip
/// </summary>
public void UnZip()
{
StartCoroutine(UnzipWithPath());
}
private int doneCount;
private int indicatorStep = 1;
private float currentComSize;
/// <summary>
/// 解压缩
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public IEnumerator UnzipWithPath()
{
FileInfo fileInfo = new FileInfo(zipPath);
slider.gameObject.SetActive(true);
Debug.Log("Length:" + fileInfo.Length);
//ZipEntry:文件条目 就是该目录下所有的文件列表(也就是所有文件的路径)
ZipEntry zip = null;
//输入的所有的文件流都是存储在这里面的
//ZipInputStream zipInStream = null;
//读取文件流到zipInputStream
ZipInputStream zipInStream = new ZipInputStream(File.OpenRead(zipPath));
//循环读取Zip目录下的所有文件
while ((zip = zipInStream.GetNextEntry()) != null)
{
UnzipFile(zip, zipInStream);
currentComSize += zip.CompressedSize;
float sliderValue = (currentComSize / fileInfo.Length) * 100.0f;
doneCount++;
Debug.Log("进度:" + sliderValue);
sliderText.text = "当前已解压" + doneCount + "个文件,已解压" + sliderValue.ToString("F2") + "%";
slider.value = currentComSize / fileInfo.Length;
if (doneCount % indicatorStep == 0)
{
yield return new WaitForEndOfFrame();
}
}
try
{
zipInStream.Close();
}
catch (Exception ex)
{
Debug.Log("UnZip Error");
throw ex;
}
Debug.Log("解压完成:" + zipPath);
slider.gameObject.SetActive(false);
}
public void UnzipFile(ZipEntry zip, ZipInputStream zipInStream)
{
try
{
//文件名
string fileName = Path.GetFileName(zip.Name);
//文件地址
string filePath = Path.Combine(outPath, zip.Name);
//文件夹名
string directoryName = Path.GetDirectoryName(filePath);
// 创建压缩文件中文件的位置
if (directoryName.Length > 0)
{
Directory.CreateDirectory(directoryName);
}
//文件名不为空
if (!string.IsNullOrEmpty(zip.Name))
{
FileStream fs = null;
//当前文件夹下有该文件 删掉 重新创建
if (File.Exists(filePath))
{
File.Delete(filePath);
}
fs = File.Create(filePath);
int size = 2048;
byte[] data = new byte[2048];
//每次读取2MB 直到把这个内容读完
while (true)
{
size = zipInStream.Read(data, 0, data.Length);
//小于0, 也就读完了当前的流
if (size > 0)
{
fs.Write(data, 0, size);
}
else
{
break;
}
}
fs.Close();
}
}
catch (Exception e)
{
throw new Exception();
}
}
}
ICSharpCode.SharpZipLib.dll下载链接:下载链接 提取码:5ow0
踩坑备注
打包PC端测试的时候报错:
解决方案:
将I18N.DLL 和 I18N.CJK.DLL 从Unity安装目录(Editor\Data\Mono\lib\mono\unity 和 Editor\Data\Mono\lib\mono\2.0 两个目录下都存在)拷贝到项目目录的Assets目录下,然后重新编译出包,可正常运行。
方法二:
.NET4.5以上版本支持:
using System.IO.Compression;
//zipPath:zip文件的路径
//outPath:解压路径
ZipFile.ExtractToDirectory(zipPath, outPath);
注意:
这两种方法均不支持双层文件夹,方法一的使用有部分局限性,如果文件夹层级太多可能会判断有误不能解压。
方法三:
压缩文件和文件夹、对文件和文件夹进行解压:
using System.IO;
using UnityEngine;
using ICSharpCode.SharpZipLib.Zip;
`
public static class ZipHelper
{
#region ZipCallback
public abstract class ZipCallback
{
/// <summary>
/// 压缩单个文件或文件夹前执行的回调
/// </summary>
/// <param name="_entry"></param>
/// <returns>如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹</returns>
public virtual bool OnPreZip(ZipEntry _entry)
{
return true;
}
/// <summary>
/// 压缩单个文件或文件夹后执行的回调
/// </summary>
/// <param name="_entry"></param>
public virtual void OnPostZip(ZipEntry _entry) { }
/// <summary>
/// 压缩执行完毕后的回调
/// </summary>
/// <param name="_result">true表示压缩成功,false表示压缩失败</param>
public virtual void OnFinished(bool _result) { }
}
#endregion
#region UnzipCallback
public abstract class UnzipCallback
{
/// <summary>
/// 解压单个文件或文件夹前执行的回调
/// </summary>
/// <param name="_entry"></param>
/// <returns>如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹</returns>
public virtual bool OnPreUnzip(ZipEntry _entry)
{
return true;
}
/// <summary>
/// 解压单个文件或文件夹后执行的回调
/// </summary>
/// <param name="_entry"></param>
public virtual void OnPostUnzip(ZipEntry _entry) { }
/// <summary>
/// 解压执行完毕后的回调
/// </summary>
/// <param name="_result">true表示解压成功,false表示解压失败</param>
public virtual void OnFinished(bool _result) { }
}
#endregion
/// <summary>
/// 压缩文件和文件夹
/// </summary>
/// <param name="_fileOrDirectoryArray">文件夹路径和文件名</param>
/// <param name="_outputPathName">压缩后的输出路径文件名</param>
/// <param name="_password">压缩密码</param>
/// <param name="_zipCallback">ZipCallback对象,负责回调</param>
/// <returns></returns>
public static bool Zip(string[] _fileOrDirectoryArray, string _outputPathName, string _password = null, ZipCallback _zipCallback = null)
{
if ((null == _fileOrDirectoryArray) || string.IsNullOrEmpty(_outputPathName))
{
if (null != _zipCallback)
_zipCallback.OnFinished(false);
return false;
}
ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(_outputPathName));
zipOutputStream.SetLevel(6); // 压缩质量和压缩速度的平衡点
if (!string.IsNullOrEmpty(_password))
zipOutputStream.Password = _password;
for (int index = 0; index < _fileOrDirectoryArray.Length; ++index)
{
bool result = false;
string fileOrDirectory = _fileOrDirectoryArray[index];
if (Directory.Exists(fileOrDirectory))
result = ZipDirectory(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
else if (File.Exists(fileOrDirectory))
result = ZipFile(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
if (!result)
{
if (null != _zipCallback)
_zipCallback.OnFinished(false);
return false;
}
}
zipOutputStream.Finish();
zipOutputStream.Close();
if (null != _zipCallback)
_zipCallback.OnFinished(true);
return true;
}
/// <summary>
/// 解压Zip包
/// </summary>
/// <param name="_filePathName">Zip包的文件路径名</param>
/// <param name="_outputPath">解压输出路径</param>
/// <param name="_password">解压密码</param>
/// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
/// <returns></returns>
public static bool UnzipFile(string _filePathName, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
{
if (string.IsNullOrEmpty(_filePathName) || string.IsNullOrEmpty(_outputPath))
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
try
{
return UnzipFile(File.OpenRead(_filePathName), _outputPath, _password, _unzipCallback);
}
catch (System.Exception _e)
{
Debug.LogError("[ZipUtility.UnzipFile]: " + _e.ToString());
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
}
/// <summary>
/// 解压Zip包
/// </summary>
/// <param name="_fileBytes">Zip包字节数组</param>
/// <param name="_outputPath">解压输出路径</param>
/// <param name="_password">解压密码</param>
/// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
/// <returns></returns>
public static bool UnzipFile(byte[] _fileBytes, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
{
if ((null == _fileBytes) || string.IsNullOrEmpty(_outputPath))
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
bool result = UnzipFile(new MemoryStream(_fileBytes), _outputPath, _password, _unzipCallback);
if (!result)
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
}
return result;
}
/// <summary>
/// 解压Zip包
/// </summary>
/// <param name="_inputStream">Zip包输入流</param>
/// <param name="_outputPath">解压输出路径</param>
/// <param name="_password">解压密码</param>
/// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
/// <returns></returns>
public static bool UnzipFile(Stream _inputStream, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
{
if ((null == _inputStream) || string.IsNullOrEmpty(_outputPath))
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
// 创建文件目录
if (!Directory.Exists(_outputPath))
Directory.CreateDirectory(_outputPath);
/*
* ICSharpCode.SharpZipLib.Zip.ZipConstants.DefaultCodePage默认为437(美国/加拿大英语),
* 如果被解压的文件不是437编码将报CodePage 437 not supported错误。
*/
#if UNITY_STANDALONE_WIN
ZipConstants.DefaultCodePage =System.Text.Encoding.UTF8.CodePage;
#endif
// 解压Zip包
ZipEntry entry = null;
using (ZipInputStream zipInputStream = new ZipInputStream(_inputStream))
{
if (!string.IsNullOrEmpty(_password))
zipInputStream.Password = _password;
while (null != (entry = zipInputStream.GetNextEntry()))
{
if (string.IsNullOrEmpty(entry.Name))
continue;
if ((null != _unzipCallback) && !_unzipCallback.OnPreUnzip(entry))
continue; // 过滤
string filePathName = Path.Combine(_outputPath, entry.Name);
// 创建文件目录
if (entry.IsDirectory)
{
Directory.CreateDirectory(filePathName);
continue;
}
// 写入文件
try
{
using (FileStream fileStream = File.Create(filePathName))
{
byte[] bytes = new byte[1024];
while (true)
{
int count = zipInputStream.Read(bytes, 0, bytes.Length);
if (count > 0)
fileStream.Write(bytes, 0, count);
else
{
if (null != _unzipCallback)
_unzipCallback.OnPostUnzip(entry);
break;
}
}
}
}
catch (System.Exception _e)
{
Debug.LogError("[ZipUtility.UnzipFile]: " + _e.ToString());
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
}
}
if (null != _unzipCallback)
_unzipCallback.OnFinished(true);
return true;
}
/// <summary>
/// 压缩文件
/// </summary>
/// <param name="_filePathName">文件路径名</param>
/// <param name="_parentRelPath">要压缩的文件的父相对文件夹</param>
/// <param name="_zipOutputStream">压缩输出流</param>
/// <param name="_zipCallback">ZipCallback对象,负责回调</param>
/// <returns></returns>
private static bool ZipFile(string _filePathName, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
{
//Crc32 crc32 = new Crc32();
ZipEntry entry = null;
FileStream fileStream = null;
try
{
string entryName = _parentRelPath + '/' + Path.GetFileName(_filePathName);
entry = new ZipEntry(entryName);
entry.DateTime = System.DateTime.Now;
if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
return true; // 过滤
fileStream = File.OpenRead(_filePathName);
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, buffer.Length);
fileStream.Close();
entry.Size = buffer.Length;
//crc32.Reset();
//crc32.Update(buffer);
//entry.Crc = crc32.Value;
_zipOutputStream.PutNextEntry(entry);
_zipOutputStream.Write(buffer, 0, buffer.Length);
}
catch (System.Exception _e)
{
Debug.LogError("[ZipUtility.ZipFile]: " + _e.ToString());
return false;
}
finally
{
if (null != fileStream)
{
fileStream.Close();
fileStream.Dispose();
}
}
if (null != _zipCallback)
_zipCallback.OnPostZip(entry);
return true;
}
/// <summary>
/// 压缩文件夹
/// </summary>
/// <param name="_path">要压缩的文件夹</param>
/// <param name="_parentRelPath">要压缩的文件夹的父相对文件夹</param>
/// <param name="_zipOutputStream">压缩输出流</param>
/// <param name="_zipCallback">ZipCallback对象,负责回调</param>
/// <returns></returns>
private static bool ZipDirectory(string _path, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
{
ZipEntry entry = null;
try
{
string entryName = Path.Combine(_parentRelPath, Path.GetFileName(_path) + '/');
entry = new ZipEntry(entryName);
entry.DateTime = System.DateTime.Now;
entry.Size = 0;
if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
return true; // 过滤
_zipOutputStream.PutNextEntry(entry);
_zipOutputStream.Flush();
string[] files = Directory.GetFiles(_path);
for (int index = 0; index < files.Length; ++index)
ZipFile(files[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback);
}
catch (System.Exception _e)
{
Debug.LogError("[ZipUtility.ZipDirectory]: " + _e.ToString());
return false;
}
string[] directories = Directory.GetDirectories(_path);
for (int index = 0; index < directories.Length; ++index)
{
if (!ZipDirectory(directories[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback))
return false;
}
if (null != _zipCallback)
_zipCallback.OnPostZip(entry);
return true;
}
}``