irc-netcore-api/IRaCIS.Core.Infrastructure/Extention/SevenZipCompressor.cs

206 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using SharpCompress.Archives;
using SharpCompress.Common;
using SharpCompress.Readers;
using SharpCompress.Writers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace IRaCIS.Core.Infrastructure.Extention
{
/// <summary>
/// 7z压缩
/// </summary>
public static class SevenZipCompressor
{
/// <summary>
/// 将多个文件压缩到一个内存流中可保存为zip文件方便于web方式下载
/// </summary>
/// <param name="files">多个文件路径文件或文件夹或网络路径http/https</param>
/// <param name="rootdir"></param>
/// <returns>文件流</returns>
public static MemoryStream ZipStream(List<string> files, string rootdir = "")
{
using var archive = CreateZipArchive(files, rootdir);
var ms = new MemoryStream();
archive.SaveTo(ms, new WriterOptions(CompressionType.Deflate)
{
LeaveStreamOpen = true,
ArchiveEncoding = new ArchiveEncoding()
{
Default = Encoding.UTF8
}
});
return ms;
}
/// <summary>
/// 压缩多个文件
/// </summary>
/// <param name="files">多个文件路径,文件或文件夹</param>
/// <param name="zipFile">压缩到...</param>
/// <param name="rootdir">压缩包内部根文件夹</param>
/// <param name="archiveType"></param>
public static void Zip(List<string> files, string zipFile, string rootdir = "", ArchiveType archiveType = ArchiveType.SevenZip)
{
using var archive = CreateZipArchive(files, rootdir, archiveType);
archive.SaveTo(zipFile, new WriterOptions(CompressionType.Deflate)
{
LeaveStreamOpen = true,
ArchiveEncoding = new ArchiveEncoding()
{
Default = Encoding.UTF8
}
});
}
/// <summary>
/// 解压文件,自动检测压缩包类型
/// </summary>
/// <param name="compressedFile">rar文件</param>
/// <param name="dir">解压到...</param>
/// <param name="ignoreEmptyDir">忽略空文件夹</param>
public static void Decompress(string compressedFile, string dir = "", bool ignoreEmptyDir = true)
{
if (string.IsNullOrEmpty(dir))
{
dir = Path.GetDirectoryName(compressedFile);
}
using Stream stream = File.OpenRead(compressedFile);
using var reader = ReaderFactory.Open(stream);
while (reader.MoveToNextEntry())
{
if (ignoreEmptyDir)
{
reader.WriteEntryToDirectory(dir, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
else
{
if (!reader.Entry.IsDirectory)
{
reader.WriteEntryToDirectory(dir, new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
}
}
/// <summary>
/// 创建zip包
/// </summary>
/// <param name="files"></param>
/// <param name="rootdir"></param>
/// <param name="archiveType"></param>
/// <returns></returns>
private static IWritableArchive CreateZipArchive(List<string> files, string rootdir, ArchiveType archiveType = ArchiveType.SevenZip)
{
var archive = ArchiveFactory.Create(archiveType);
var dic = GetFileEntryMaps(files);
var remoteUrls = files.Distinct().Where(s => s.StartsWith("http")).Select(s =>
{
try
{
return new Uri(s);
}
catch (UriFormatException)
{
return null;
}
}).Where(u => u != null).ToList();
foreach (var pair in dic)
{
archive.AddEntry(Path.Combine(rootdir, pair.Value), pair.Key);
}
if (!remoteUrls.Any())
{
return archive;
}
var streams = new ConcurrentDictionary<string, Stream>();
using var httpClient = new HttpClient();
Parallel.ForEach(remoteUrls, url =>
{
httpClient.GetAsync(url).ContinueWith(async t =>
{
if (t.IsCompleted)
{
var res = await t;
if (res.IsSuccessStatusCode)
{
Stream stream = await res.Content.ReadAsStreamAsync();
streams[Path.Combine(rootdir, Path.GetFileName(HttpUtility.UrlDecode(url.AbsolutePath)))] = stream;
}
}
}).Wait();
});
foreach (var kv in streams)
{
archive.AddEntry(kv.Key, kv.Value, true);
}
return archive;
}
/// <summary>
/// 获取文件路径和zip-entry的映射
/// </summary>
/// <param name="files"></param>
/// <returns></returns>
private static Dictionary<string, string> GetFileEntryMaps(List<string> files)
{
var fileList = new List<string>();
void GetFilesRecurs(string path)
{
//遍历目标文件夹的所有文件
fileList.AddRange(Directory.GetFiles(path));
//遍历目标文件夹的所有文件夹
foreach (string directory in Directory.GetDirectories(path))
{
GetFilesRecurs(directory);
}
}
files.Where(s => !s.StartsWith("http")).ForEach(s =>
{
if (Directory.Exists(s))
{
GetFilesRecurs(s);
}
else
{
fileList.Add(s);
}
});
if (!fileList.Any())
{
return new Dictionary<string, string>();
}
var dirname = new string(fileList.First().Substring(0, fileList.Min(s => s.Length)).TakeWhile((c, i) => fileList.All(s => s[i] == c)).ToArray());
if (!Directory.Exists(dirname))
{
dirname = Directory.GetParent(dirname).FullName;
}
var dic = fileList.ToDictionary(s => s, s => s.Substring(dirname.Length));
return dic;
}
}
}