
using System.IO;
using System.IO.Compression;
void Main()
{
var files = qk.Selection.GetFiles();
if (files == null || files.Length == 0)
{
qk.Ui.Notify("请先在资源管理器中选中要打包的文件或文件夹", "warn", "打包选中文件");
return;
}
var items = new List<string>();
foreach (var f in files)
{
if (string.IsNullOrWhiteSpace(f)) continue;
var p = f.TrimEnd('\\', '/');
if (p.Length == 0) continue;
if (!File.Exists(p) && !Directory.Exists(p)) continue;
if (!items.Any(x => string.Equals(x, p, StringComparison.OrdinalIgnoreCase))) items.Add(p);
}
if (items.Count == 0)
{
qk.Ui.Notify("选中的项目不可用(驱动器根目录无法打包)", "warn", "打包选中文件");
return;
}
// 去掉被已选中文件夹包含的子项,避免重复打包
var roots = new List<string>();
foreach (var p in items)
{
var nested = false;
foreach (var r in items)
{
if (string.Equals(p, r, StringComparison.OrdinalIgnoreCase)) continue;
var prefix = r + "\\";
if (p.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { nested = true; break; }
}
if (!nested) roots.Add(p);
}
var baseDir = Path.GetDirectoryName(roots[0]);
if (string.IsNullOrEmpty(baseDir) || !Directory.Exists(baseDir))
{
qk.Ui.Notify("无法确定输出目录", "error", "打包选中文件");
return;
}
string baseName;
if (roots.Count == 1)
{
baseName = Directory.Exists(roots[0])
? Path.GetFileName(roots[0])
: Path.GetFileNameWithoutExtension(roots[0]);
}
else
{
baseName = new DirectoryInfo(baseDir).Name;
}
if (string.IsNullOrWhiteSpace(baseName)) baseName = "打包";
var zipPath = UniquePath(Path.Combine(baseDir, baseName + ".zip"));
var tempZip = Path.Combine(qk.Files.GetRunTempDirectory(), "archive.tmp");
var count = 0;
var bytes = 0L;
void AddFile(ZipArchive zip, string path, string entryName)
{
var name = entryName.Replace('\\', '/');
var entry = zip.CreateEntry(name, CompressionLevel.Optimal);
entry.LastWriteTime = File.GetLastWriteTime(path);
using (var src = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var dst = entry.Open())
{
src.CopyTo(dst);
}
count++;
bytes += new FileInfo(path).Length;
}
void AddDir(ZipArchive zip, string dir, string prefix)
{
var children = Directory.GetFileSystemEntries(dir);
if (children.Length == 0)
{
var marker = zip.CreateEntry(prefix.Replace('\\', '/') + "/", CompressionLevel.NoCompression);
marker.LastWriteTime = Directory.GetLastWriteTime(dir);
return;
}
foreach (var child in children)
{
var entryName = prefix + "/" + Path.GetFileName(child);
if (Directory.Exists(child)) AddDir(zip, child, entryName);
else AddFile(zip, child, entryName);
}
}
try
{
using (var fs = new FileStream(tempZip, FileMode.Create, FileAccess.ReadWrite))
using (var zip = new ZipArchive(fs, ZipArchiveMode.Create))
{
foreach (var root in roots)
{
if (Directory.Exists(root)) AddDir(zip, root, Path.GetFileName(root));
else AddFile(zip, root, Path.GetFileName(root));
}
}
File.Move(tempZip, zipPath);
var sizeText = bytes >= 1048576L
? (bytes / 1048576.0).ToString("0.##") + " MB"
: (bytes / 1024.0).ToString("0.#") + " KB";
qk.Ui.Notify(string.Format("已打包 {0} 个文件({1})\n{2}", count, sizeText, zipPath), "success", "打包选中文件", 5000);
}
catch (Exception ex)
{
qk.Ui.Notify("打包失败:" + ex.Message, "error", "打包选中文件", -1);
}
}
string UniquePath(string path)
{
if (!File.Exists(path) && !Directory.Exists(path)) return path;
var dir = Path.GetDirectoryName(path) ?? "";
var name = Path.GetFileNameWithoutExtension(path);
var ext = Path.GetExtension(path);
for (var i = 2; i < 1000; i++)
{
var candidate = Path.Combine(dir, name + " (" + i + ")" + ext);
if (!File.Exists(candidate) && !Directory.Exists(candidate)) return candidate;
}
return path;
}