초기 커밋.
This commit is contained in:
247
Assets/Scripts/UVC/util/Zipper.cs
Normal file
247
Assets/Scripts/UVC/util/Zipper.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace UVC.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Zipper 클래스는 압축 파일(Zip 및 7z)의 압축 해제 기능을 제공합니다.
|
||||
/// 7zip 라이브러리를 사용하며, 압축 해제 진행률을 실시간으로 추적할 수 있습니다.
|
||||
/// 7zip 사용. https://assetstore.unity.com/packages/tools/input-management/7zip-lzma-lz4-fastlz-zip-gzip-brotli-multiplatform-plugins-12674
|
||||
/// </summary>
|
||||
public class Zipper
|
||||
{
|
||||
|
||||
// zip 보관 파일을 압축하지 않은 현재 파일 수로 변경하는 단일 항목 정수 배열입니다.
|
||||
// decompress_File 기능을 실행할 때 getTotalFiles 기능으로 반환된 총 파일 수와 이 int를 비교하여 zip에 여러 개의 파일이 포함된 경우 추출의 진행 상황을 파악한다.
|
||||
// 여러 개의 스레드를 사용하는 경우 다른 스레드에 다른 진행 정수를 사용해야 합니다.그렇지 않으면 공유 위반이 발생합니다.
|
||||
private int[] progress;
|
||||
|
||||
/// <summary>
|
||||
/// 개별 파일의 압축 해제 진행률(바이트 단위)을 나타내는 배열입니다.
|
||||
/// </summary>
|
||||
private ulong[] progress2;
|
||||
/// <summary>
|
||||
/// 압축 파일의 경로를 저장합니다.
|
||||
/// </summary>
|
||||
private string zipFilePath;
|
||||
/// <summary>
|
||||
/// 압축 해제가 완료되었는지 여부를 나타냅니다.
|
||||
/// </summary>
|
||||
private bool isComplete = false;
|
||||
/// <summary>
|
||||
/// 압축 해제 진행률(0.0 ~ 1.0)을 나타냅니다.
|
||||
/// </summary>
|
||||
private float percent = 0;
|
||||
/// <summary>
|
||||
/// 압축 해제 진행 상황을 콜백으로 전달하는 액션입니다.
|
||||
/// </summary>
|
||||
private Action<long, long, float> OnProgress;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 압축 파일을 해제합니다.
|
||||
/// 파일 형식(Zip 또는 7z)에 따라 적절한 메서드를 호출합니다.
|
||||
/// </summary>
|
||||
/// <param name="zipFilePath">압축 파일 경로</param>
|
||||
/// <param name="decompressFolderPath">압축 해제 대상 폴더 경로</param>
|
||||
/// <param name="OnProgress">압축 해제 진행 상황을 전달하는 콜백</param>
|
||||
/// <returns>압축 해제 결과 메시지</returns>
|
||||
/// <example>
|
||||
/// Zipper zipper = new Zipper();
|
||||
/// string result = await zipper.Decompress("path/to/file.zip", "path/to/output", (current, total, percent) =>
|
||||
/// {
|
||||
/// Debug.Log($"Progress: {percent * 100}%");
|
||||
/// });
|
||||
/// if (result == null)
|
||||
/// {
|
||||
/// Debug.Log("Decompression successful!");
|
||||
/// }
|
||||
/// else
|
||||
/// {
|
||||
/// Debug.LogError($"Decompression failed: {result}");
|
||||
/// }
|
||||
/// </example>
|
||||
public async UniTask<string> Decompress(string zipFilePath, string decompressFolderPath, Action<long, long, float> OnProgress)
|
||||
{
|
||||
if (zipFilePath.ToLower().Contains(".zip"))
|
||||
{
|
||||
return await DecompressZip(zipFilePath, decompressFolderPath, OnProgress);
|
||||
}
|
||||
else if (zipFilePath.ToLower().Contains(".7z"))
|
||||
{
|
||||
return await Decompress7Zip(zipFilePath, decompressFolderPath, OnProgress);
|
||||
}
|
||||
return "Unsupported compressed file";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zip 파일을 압축 해제합니다.
|
||||
/// </summary>
|
||||
/// <param name="zipFilePath">압축 파일 경로</param>
|
||||
/// <param name="decompressFolderPath">압축 해제 대상 폴더 경로</param>
|
||||
/// <param name="OnProgress">압축 해제 진행 상황을 전달하는 콜백</param>
|
||||
/// <returns>압축 해제 결과 메시지</returns>
|
||||
/// <example>
|
||||
/// Zipper zipper = new Zipper();
|
||||
/// string result = await zipper.DecompressZip("path/to/file.zip", "path/to/output", (current, total, percent) =>
|
||||
/// {
|
||||
/// Debug.Log($"Progress: {percent * 100}%");
|
||||
/// });
|
||||
/// if (result == null)
|
||||
/// {
|
||||
/// Debug.Log("Decompression successful!");
|
||||
/// }
|
||||
/// else
|
||||
/// {
|
||||
/// Debug.LogError($"Decompression failed: {result}");
|
||||
/// }
|
||||
/// </example>
|
||||
public async UniTask<string> DecompressZip(string zipFilePath, string decompressFolderPath, Action<long, long, float> OnProgress)
|
||||
{
|
||||
progress = new int[1];
|
||||
progress2 = new ulong[1];
|
||||
isComplete = false;
|
||||
this.zipFilePath = zipFilePath;
|
||||
this.OnProgress = OnProgress;
|
||||
|
||||
if (lzip.validateFile(zipFilePath))
|
||||
{
|
||||
//getFileInfo zip 내의 콘텐츠의 총 압축되지 않은 바이트를 반환한다.
|
||||
ulong totalBytes = lzip.getFileInfo(zipFilePath);
|
||||
CountPercentZipAsync(totalBytes).Forget();
|
||||
int result = await UniTask.RunOnThreadPool(() =>
|
||||
{
|
||||
return lzip.decompress_File(zipFilePath, decompressFolderPath, progress, null, progress2);
|
||||
});
|
||||
isComplete = true;
|
||||
if (result == 1) //success
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
//-1 = could not initialize zip archive.
|
||||
//-2 = failed extraction
|
||||
//- 6 = IntPtr buffer had no valid buffer length parameter passed.
|
||||
string errorMessage = "Unknown error";
|
||||
if (result == -1) errorMessage = "could not initialize zip archive.";
|
||||
else if (result == -2) errorMessage = "failed extraction.";
|
||||
else if (result == -6) errorMessage = "IntPtr buffer had no valid buffer length parameter passed.";
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
return "invalidate File";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zip 파일의 압축 해제 진행률을 계산합니다.
|
||||
/// </summary>
|
||||
/// <param name="totalBytes">압축 해제 대상 파일의 총 바이트 수</param>
|
||||
private async UniTaskVoid CountPercentZipAsync(ulong totalBytes)
|
||||
{
|
||||
|
||||
percent = (float)progress2[0] / (float)totalBytes;
|
||||
|
||||
//Debug.Log($"CountPercentAsync totalBytes:{totalBytes} progress:{progress[0]} progress2:{progress2[0]} {percent}");
|
||||
if (OnProgress != null) OnProgress((long)progress2[0], (long)totalBytes, percent);
|
||||
if (percent == 1) isComplete = true;
|
||||
if (!isComplete)
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromMilliseconds(100));//0.1초에 한번씩
|
||||
CountPercentZipAsync(totalBytes).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 7z 파일을 압축 해제합니다.
|
||||
/// </summary>
|
||||
/// <param name="zipFilePath">압축 파일 경로</param>
|
||||
/// <param name="decompressFolderPath">압축 해제 대상 폴더 경로</param>
|
||||
/// <param name="OnProgress">압축 해제 진행 상황을 전달하는 콜백</param>
|
||||
/// <returns>압축 해제 결과 메시지</returns>
|
||||
/// <example>
|
||||
/// Zipper zipper = new Zipper();
|
||||
/// string result = await zipper.Decompress7Zip("path/to/file.7z", "path/to/output", (current, total, percent) =>
|
||||
/// {
|
||||
/// Debug.Log($"Progress: {percent * 100}%");
|
||||
/// });
|
||||
/// if (result == null)
|
||||
/// {
|
||||
/// Debug.Log("Decompression successful!");
|
||||
/// }
|
||||
/// else
|
||||
/// {
|
||||
/// Debug.LogError($"Decompression failed: {result}");
|
||||
/// }
|
||||
/// </example>
|
||||
public async UniTask<string> Decompress7Zip(string zipFilePath, string decompressFolderPath, Action<long, long, float> OnProgress)
|
||||
{
|
||||
progress = new int[1] { 0 };
|
||||
isComplete = false;
|
||||
this.zipFilePath = zipFilePath;
|
||||
this.OnProgress = OnProgress;
|
||||
|
||||
// 참조된 progress int는 압축 해제 중인 파일의 현재 인덱스를 나타냅니다. 별도의 스레드에서 사용하여 실시간으로 표시합니다.
|
||||
// (thread에서) 실시간 바이트 레벨 압축해제 진행을 얻기 위해서는 두 가지 방법이 있습니다.
|
||||
// 1. lzma.get7zSize 함수를 사용하여 파일의 총 압축되지 않은 크기를 구하고 lzma.getBytesWritten 함수를 호출하여 실시간으로 작성된 바이트들과 비교한다.
|
||||
// 2. lzma.getFileSize(또는 FileBuffers의 버퍼 길이)를 사용하여 파일 크기를 구하고 lzma.getBytesRead 기능을 호출하여 실시간으로 읽는 바이트들과 비교한다.
|
||||
//FileInfo fileInfo = new(zipFilePath);
|
||||
//FileSecurity fsecurity = fileInfo.GetAccessControl();
|
||||
//var id = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Trim();
|
||||
//var name = id.Split("\\");
|
||||
//fsecurity.AddAccessRule(new FileSystemAccessRule(new NTAccount(name[1]), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
|
||||
//fileInfo.SetAccessControl(fsecurity);
|
||||
long totalBytes = lzma.getFileSize(zipFilePath);
|
||||
CountPercent7ZipAsync(totalBytes, true).Forget();
|
||||
int result = await UniTask.RunOnThreadPool(() =>
|
||||
{
|
||||
return lzma.doDecompress7zip(zipFilePath, decompressFolderPath, progress, true, true);
|
||||
});
|
||||
isComplete = true;
|
||||
if (result == 1) //success
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
//1 : OK
|
||||
//2 : Could not find requested file in archive
|
||||
//- 1 : Could not open input(7z) file
|
||||
//- 2 : Decoder doesn't support this archive
|
||||
//- 3 : Can not allocate memory
|
||||
//-5 : Unknown error
|
||||
//-6 : File IO error
|
||||
string errorMessage = "Unknown error";
|
||||
if (result == 2) errorMessage = "Could not find requested file in archive";
|
||||
else if (result == -1) errorMessage = "Could not open input(7z) file";
|
||||
else if (result == -2) errorMessage = "Decoder doesn't support this archive";
|
||||
else if (result == -3) errorMessage = "Can not allocate memory";
|
||||
else if (result == -6) errorMessage = "File IO error";
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 7z 파일의 압축 해제 진행률을 계산합니다.
|
||||
/// </summary>
|
||||
/// <param name="totalBytes">압축 해제 대상 파일의 총 바이트 수</param>
|
||||
/// <param name="isFirst">첫 번째 호출 여부</param>
|
||||
private async UniTaskVoid CountPercent7ZipAsync(long totalBytes, bool isFirst = false)
|
||||
{
|
||||
if (!isFirst)
|
||||
{
|
||||
long readByted = (long)lzma.getBytesRead();
|
||||
percent = (float)readByted / (float)totalBytes;
|
||||
//Debug.Log($"CountPercent7ZipAsync totalBytes:{totalBytes} progress:{progress}");
|
||||
if (OnProgress != null) OnProgress(readByted, totalBytes, percent);
|
||||
if (percent == 1) isComplete = true;
|
||||
}
|
||||
if (!isComplete)
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromMilliseconds(100));//0.1초에 한번씩
|
||||
CountPercent7ZipAsync(totalBytes).Forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user