我已经看过很多关于如何在c#中压缩单个文件的教程。但我需要能够创建一个普通的* .zip文件,而不仅仅是一个文件。 .NET中有什么可以做到的吗?你会建议什么(记住我是在严格的规则下,不能使用其他库)
谢谢
答案 0 :(得分:61)
对于遇到这个问题的其他人来说,只是对此进行更新。
从.NET 4.5开始,您可以使用System.IO.Compression
将目录压缩为zip文件。您必须添加System.IO.Compression.FileSystem
作为参考,因为默认情况下未引用它。然后你可以写:
System.IO.Compression.ZipFile.CreateFromDirectory(dirPath, zipFile);
唯一可能的问题是此程序集不适用于Windows应用商店。
答案 1 :(得分:27)
您现在可以使用.NET 4.5中提供的ZipArchive类(System.IO.Compression.ZipArchive)
示例:生成PDF文件的zip文件
using (var fileStream = new FileStream(@"C:\temp\temp.zip", FileMode.CreateNew))
{
using (var archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true))
{
foreach (var creditNumber in creditNumbers)
{
var pdfBytes = GeneratePdf(creditNumber);
var fileName = "credit_" + creditNumber + ".pdf";
var zipArchiveEntry = archive.CreateEntry(fileName, CompressionLevel.Fastest);
using (var zipStream = zipArchiveEntry.Open())
zipStream.Write(pdfBytes, 0, pdfBytes.Length);
}
}
}
}
答案 2 :(得分:20)
以下是您可能会考虑的一些资源: Creating Zip archives in .NET (without an external library like SharpZipLib)
Zip Your Streams with System.IO.Packaging
我的建议和偏好是使用system.io.packacking。这可以减少您的依赖关系(只是框架)。 Jgalloway的帖子(第一个参考)提供了一个将两个文件添加到zip文件的好例子。是的,它更冗长,但您可以轻松创建一个外观(在某种程度上,他的AddFileToZip可以做到这一点)。
HTH
答案 3 :(得分:19)
我的2美分:
using (ZipArchive archive = ZipFile.Open(zFile, ZipArchiveMode.Create))
{
foreach (var fPath in filePaths)
{
archive.CreateEntryFromFile(fPath,Path.GetFileName(fPath));
}
}
因此可以直接从files / dirs创建Zip文件。
答案 4 :(得分:17)
编辑:如果您使用的是.Net 4.5或更高版本,则为built-in to the framework
对于早期版本或更多控件,您可以按照here on CodeProject by Gerald Gibson Jr概述使用Windows的shell函数。
我已将以下文章文本复制为书面文件(原始许可证:public domain)
使用Windows Shell API和C
压缩Zip文件简介
这是我撰写的有关解压缩Zip文件的文章的后续文章。使用此代码,您可以使用C#中的Windows Shell API压缩Zip文件,而无需显示上面显示的“复制进度”窗口。通常,当您使用Shell API压缩Zip文件时,即使您设置选项告诉Windows不显示它,它也会显示“复制进度”窗口。为了解决这个问题,您将Shell API代码移动到单独的可执行文件中,然后使用.NET Process类启动该可执行文件,确保将进程窗口样式设置为“Hidden”。
背景
是否需要压缩Zip文件并且需要比许多免费压缩库更好的Zip?即你需要压缩文件夹和子文件夹以及文件。 Windows Zipping可以压缩的不仅仅是单个文件。您只需要一种以编程方式让Windows静默压缩这些Zip文件的方法。当然,您可以在其中一个商业Zip组件上花费300美元,但如果你需要的只是压缩文件夹层次结构,那么很难免费。
使用代码
以下代码显示如何使用Windows Shell API压缩Zip文件。首先,您创建一个空的Zip文件。为此,请创建一个正确构造的字节数组,然后将该数组保存为扩展名为“.zip”的文件。我怎么知道要放入数组的字节数?好吧,我只是使用Windows来创建一个Zip文件,里面压缩了一个文件。然后我用Windows打开了Zip并删除了压缩文件。这给我留下了一个空的Zip。接下来,我在十六进制编辑器(Visual Studio)中打开空Zip文件,查看十六进制字节值,并使用Windows Calc将它们转换为十进制,并将这些十进制值复制到我的字节数组代码中。源文件夹指向要压缩的文件夹。目标文件夹指向刚刚创建的空Zip文件。这个代码将压缩Zip文件,但它也将显示“复制进度”窗口。要使此代码有效,您还需要设置对COM库的引用。在References窗口中,转到COM选项卡,然后选择标记为'Microsoft Shell Controls and Automation'的库。
//Create an empty zip file
byte[] emptyzip = new byte[]{80,75,5,6,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
FileStream fs = File.Create(args[1]);
fs.Write(emptyzip, 0, emptyzip.Length);
fs.Flush();
fs.Close();
fs = null;
//Copy a folder and its contents into the newly created zip file
Shell32.ShellClass sc = new Shell32.ShellClass();
Shell32.Folder SrcFlder = sc.NameSpace(args[0]);
Shell32.Folder DestFlder = sc.NameSpace(args[1]);
Shell32.FolderItems items = SrcFlder.Items();
DestFlder.CopyHere(items, 20);
//Ziping a file using the Windows Shell API
//creates another thread where the zipping is executed.
//This means that it is possible that this console app
//would end before the zipping thread
//starts to execute which would cause the zip to never
//occur and you will end up with just
//an empty zip file. So wait a second and give
//the zipping thread time to get started
System.Threading.Thread.Sleep(1000);
本文附带的示例解决方案展示了如何将此代码放入控制台应用程序,然后启动此控制台应用程序以压缩Zip而不显示“复制进度”窗口。
下面的代码显示了一个按钮单击事件处理程序,其中包含用于启动控制台应用程序的代码,以便在压缩期间没有UI:
private void btnUnzip_Click(object sender, System.EventArgs e)
{
//Test to see if the user entered a zip file name
if(txtZipFileName.Text.Trim() == "")
{
MessageBox.Show("You must enter what" +
" you want the name of the zip file to be");
//Change the background color to cue the user to what needs fixed
txtZipFileName.BackColor = Color.Yellow;
return;
}
else
{
//Reset the background color
txtZipFileName.BackColor = Color.White;
}
//Launch the zip.exe console app to do the actual zipping
System.Diagnostics.ProcessStartInfo i =
new System.Diagnostics.ProcessStartInfo(
AppDomain.CurrentDomain.BaseDirectory + "zip.exe");
i.CreateNoWindow = true;
string args = "";
if(txtSource.Text.IndexOf(" ") != -1)
{
//we got a space in the path so wrap it in double qoutes
args += "\"" + txtSource.Text + "\"";
}
else
{
args += txtSource.Text;
}
string dest = txtDestination.Text;
if(dest.EndsWith(@"\") == false)
{
dest += @"\";
}
//Make sure the zip file name ends with a zip extension
if(txtZipFileName.Text.ToUpper().EndsWith(".ZIP") == false)
{
txtZipFileName.Text += ".zip";
}
dest += txtZipFileName.Text;
if(dest.IndexOf(" ") != -1)
{
//we got a space in the path so wrap it in double qoutes
args += " " + "\"" + dest + "\"";
}
else
{
args += " " + dest;
}
i.Arguments = args;
//Mark the process window as hidden so
//that the progress copy window doesn't show
i.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(i);
p.WaitForExit();
MessageBox.Show("Complete");
}
答案 5 :(得分:6)
您可以尝试SharpZipLib。是开源,平台独立的纯c#代码。
答案 6 :(得分:4)
.NET具有用于压缩System.IO.Compression命名空间中的文件的内置功能。使用此方法,您不必将额外的库作为依赖项。此功能可从.NET 2.0获得。
以下是从我链接的MSDN页面进行压缩的方法:
public static void Compress(FileInfo fi)
{
// Get the stream of the source file.
using (FileStream inFile = fi.OpenRead())
{
// Prevent compressing hidden and already compressed files.
if ((File.GetAttributes(fi.FullName) & FileAttributes.Hidden)
!= FileAttributes.Hidden & fi.Extension != ".gz")
{
// Create the compressed file.
using (FileStream outFile = File.Create(fi.FullName + ".gz"))
{
using (GZipStream Compress = new GZipStream(outFile,
CompressionMode.Compress))
{
// Copy the source file into the compression stream.
byte[] buffer = new byte[4096];
int numRead;
while ((numRead = inFile.Read(buffer, 0, buffer.Length)) != 0)
{
Compress.Write(buffer, 0, numRead);
}
Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
fi.Name, fi.Length.ToString(), outFile.Length.ToString());
}
}
}
}
答案 7 :(得分:4)
您应该查看Zip Packages
它们是普通ZIP存档的结构化版本,需要根目录中的一些元数据。所以其他ZIP工具可以打开一个包,但是Sysytem.IO.Packaging API无法打开所有ZIP文件。
答案 8 :(得分:1)
这可以通过添加对System.IO.Compression和System.IO.Compression.Filesystem的引用来完成。
示例createZipFile()方法可能如下所示:
public static void createZipFile(string inputfile, string outputfile, CompressionLevel compressionlevel)
{
try
{
using (ZipArchive za = ZipFile.Open(outputfile, ZipArchiveMode.Update))
{
//using the same file name as entry name
za.CreateEntryFromFile(inputfile, inputfile);
}
}
catch (ArgumentException)
{
Console.WriteLine("Invalid input/output file.");
Environment.Exit(-1);
}
}
<强>,其中强>
答案 9 :(得分:0)
只需使用Dot Net就可以完成一行代码。以下是从MSDN
复制的示例代码步骤1:添加对System.IO.Compression.FileSystem的引用
第2步:按照以下代码
static void Main(string[] args)
{
string startPath = @"c:\example\start";
string zipPath = @"c:\example\result.zip";
string extractPath = @"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
}
答案 10 :(得分:0)
这是我在使用上述帖子后编写的一些代码。感谢你的帮助。
此代码接受文件路径列表并从中创建一个zip文件。
public class Zip
{
private string _filePath;
public string FilePath { get { return _filePath; } }
/// <summary>
/// Zips a set of files
/// </summary>
/// <param name="filesToZip">A list of filepaths</param>
/// <param name="sZipFileName">The file name of the new zip (do not include the file extension, nor the full path - just the name)</param>
/// <param name="deleteExistingZip">Whether you want to delete the existing zip file</param>
/// <remarks>
/// Limitation - all files must be in the same location.
/// Limitation - must have read/write/edit access to folder where first file is located.
/// Will throw exception if the zip file already exists and you do not specify deleteExistingZip
/// </remarks>
public Zip(List<string> filesToZip, string sZipFileName, bool deleteExistingZip = true)
{
if (filesToZip.Count > 0)
{
if (File.Exists(filesToZip[0]))
{
// Get the first file in the list so we can get the root directory
string strRootDirectory = Path.GetDirectoryName(filesToZip[0]);
// Set up a temporary directory to save the files to (that we will eventually zip up)
DirectoryInfo dirTemp = Directory.CreateDirectory(strRootDirectory + "/" + DateTime.Now.ToString("yyyyMMddhhmmss"));
// Copy all files to the temporary directory
foreach (string strFilePath in filesToZip)
{
if (!File.Exists(strFilePath))
{
throw new Exception(string.Format("File {0} does not exist", strFilePath));
}
string strDestinationFilePath = Path.Combine(dirTemp.FullName, Path.GetFileName(strFilePath));
File.Copy(strFilePath, strDestinationFilePath);
}
// Create the zip file using the temporary directory
if (!sZipFileName.EndsWith(".zip")) { sZipFileName += ".zip"; }
string strZipPath = Path.Combine(strRootDirectory, sZipFileName);
if (deleteExistingZip == true && File.Exists(strZipPath)) { File.Delete(strZipPath); }
ZipFile.CreateFromDirectory(dirTemp.FullName, strZipPath, CompressionLevel.Fastest, false);
// Delete the temporary directory
dirTemp.Delete(true);
_filePath = strZipPath;
}
else
{
throw new Exception(string.Format("File {0} does not exist", filesToZip[0]));
}
}
else
{
throw new Exception("You must specify at least one file to zip.");
}
}
}