136 lines
5.0 KiB
C#
136 lines
5.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Linq;
|
|
|
|
namespace CommonLibrary
|
|
{
|
|
internal class ProgressStream : Stream
|
|
{
|
|
private readonly Stream insideStream;
|
|
private readonly IProgress<int> insideReadProgress;
|
|
private readonly IProgress<int> insideWriteProgress;
|
|
|
|
public ProgressStream(Stream stream, IProgress<int> readProgress, IProgress<int> writeProgress)
|
|
{
|
|
insideStream = stream;
|
|
insideReadProgress = readProgress;
|
|
insideWriteProgress = writeProgress;
|
|
}
|
|
|
|
public override bool CanRead => insideStream.CanRead;
|
|
public override bool CanSeek => insideStream.CanSeek;
|
|
public override bool CanWrite => insideStream.CanWrite;
|
|
public override long Length => insideStream.Length;
|
|
|
|
public override long Position
|
|
{
|
|
get => insideStream.Position;
|
|
set => insideStream.Position = value;
|
|
}
|
|
|
|
public override void Flush() => insideStream.Flush();
|
|
public override long Seek(long offset, SeekOrigin origin) => insideStream.Seek(offset, origin);
|
|
public override void SetLength(long value) => insideStream.SetLength(value);
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
int bytesRead = insideStream.Read(buffer, offset, count);
|
|
insideReadProgress?.Report(bytesRead);
|
|
return bytesRead;
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
insideStream.Write(buffer, offset, count);
|
|
insideWriteProgress?.Report(count);
|
|
}
|
|
}
|
|
|
|
public class ProgressPacker
|
|
{
|
|
public void Pack(string sourceDirectoryName, string packFileName, IProgress<double> progress)
|
|
{
|
|
sourceDirectoryName = Path.GetFullPath(sourceDirectoryName);
|
|
|
|
FileInfo[] sourceFiles = new DirectoryInfo(sourceDirectoryName).GetFiles("*", SearchOption.AllDirectories);
|
|
double totalBytes = sourceFiles.Sum(f => f.Length);
|
|
long currentBytes = 0;
|
|
|
|
using (ZipArchive zipArchive = ZipFile.Open(packFileName, ZipArchiveMode.Create))
|
|
{
|
|
foreach (FileInfo file in sourceFiles)
|
|
{
|
|
// 경로 구분자를 '/' 로 통일 (Windows 탐색기 호환)
|
|
string entryName = file.FullName.Substring(sourceDirectoryName.Length + 1)
|
|
.Replace(Path.DirectorySeparatorChar, '/');
|
|
|
|
ZipArchiveEntry entry = zipArchive.CreateEntry(entryName);
|
|
entry.LastWriteTime = file.LastWriteTime;
|
|
|
|
using (Stream inputStream = file.OpenRead())
|
|
using (Stream outputStream = entry.Open())
|
|
using (Stream progressStream = new ProgressStream(inputStream,
|
|
new BasicProgress<int>(i =>
|
|
{
|
|
currentBytes += i;
|
|
progress?.Report(currentBytes / totalBytes);
|
|
}), null))
|
|
{
|
|
// ✅ 방향 수정: inputStream → progressStream → outputStream
|
|
progressStream.CopyTo(outputStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UnPack(string packFileName, string destinationDirectoryName, IProgress<double> progress)
|
|
{
|
|
using (ZipArchive zipArchive = ZipFile.OpenRead(packFileName))
|
|
{
|
|
double totalBytes = zipArchive.Entries.Sum(f => f.Length);
|
|
long currentBytes = 0;
|
|
|
|
foreach (ZipArchiveEntry entry in zipArchive.Entries)
|
|
{
|
|
// 디렉터리 엔트리 건너뜀
|
|
if (string.IsNullOrEmpty(entry.Name))
|
|
continue;
|
|
|
|
string fileName = Path.Combine(destinationDirectoryName, entry.FullName);
|
|
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
|
|
|
|
using (Stream inputStream = entry.Open())
|
|
using (Stream outputStream = File.OpenWrite(fileName))
|
|
using (Stream progressStream = new ProgressStream(outputStream, null,
|
|
new BasicProgress<int>(i =>
|
|
{
|
|
currentBytes += i;
|
|
progress?.Report(currentBytes / totalBytes);
|
|
})))
|
|
{
|
|
inputStream.CopyTo(progressStream);
|
|
}
|
|
|
|
File.SetLastWriteTime(fileName, entry.LastWriteTime.LocalDateTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class BasicProgress<T> : IProgress<T>
|
|
{
|
|
private readonly Action<T> actionHandler;
|
|
|
|
public BasicProgress(Action<T> handler)
|
|
{
|
|
actionHandler = handler;
|
|
}
|
|
|
|
public void Report(T value)
|
|
{
|
|
actionHandler(value);
|
|
}
|
|
}
|
|
}
|