65.9K
CodeProject 正在变化。 阅读更多。
Home

如何在 .NET 中利用 Shell32 库作为 COM 导入 – 一个巧妙的小技巧

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (6投票s)

2009年3月16日

CPOL

3分钟阅读

viewsIcon

126811

downloadIcon

2186

使用 Shell32 库将文件或文件夹写入 Zip 文件。

引言

您是否曾想知道如何在不使用第三方库的情况下压缩文件?虽然这可能看似毫无意义,但我将解释如何做到。

背景

我之所以努力实现这一点,是为了能够使用 ExpressMaint 工具并压缩我的数据库。因此,我在这里写下了我在 Code Project 上的第一篇文章。

解构 Zip 文件

首先,这是一个技巧,所以我们需要了解 Zip 文件是如何制作的。为了演示,我使用了一个十六进制编辑器(二进制编辑器)来向您展示。

我在一个文件夹中右键单击,创建了一个空的 Zip 文件。

EmptyZipFile.jpg

太好了,现在我们看到一个 22 字节的空 Zip 文件。
然后,我们添加一个包含文本“Hello World”的文本文件,以供比较。

SimpleZipFile.jpg

对于那些想更好地理解 *.zip 文件头构成的人来说,这是头部的分解:

  • 本地文件头签名 4 字节 (0x04034b50)
  • 提取所需版本 2 字节
  • 通用目的位标志 2 字节
  • 压缩方法 2 字节
  • 最后修改文件时间 2 字节
  • 最后修改文件日期 2 字节
  • crc-32 4 字节
  • 压缩后大小 4 字节
  • 未压缩大小 4 字节
  • 文件名长度 2 字节
  • 额外字段长度 2 字节
  • 文件名(可变大小)
  • 额外字段(可变大小)

好的,看看这个,我们显然不需要处理头部中的以下字段,因为对于空文件我们只需要 22 字节。

  • 未压缩大小 4 字节
  • 文件名长度 2 字节
  • 额外字段长度 2 字节

好了,理论够了,让我们玩得开心点……

我之所以给这篇文章加上“巧妙的小技巧”的后缀,是因为我们将使用 Shell32.dll 将文件或文件夹复制到目标 Zip 文件中,而这是 Windows 原生支持的功能。
这留下了一个缺陷;我们需要一个目标文件……我们将手动创建它,因此需要了解理论。

如何在 VB.NET 和 C# 中创建 *.zip 文件。

VB.NET

Public Sub CreateZipFile(ByVal Filename As String) 'create a new empty zip file
        'Create Header of Zip File
        Dim Encoder As New System.Text.ASCIIEncoding
        Dim Header As String = "PK" & Chr(5) & Chr(6)
        Header = Header.PadRight(22, Chr(0))

        'Save file - Make sure your file ends with .zip!
        My.Computer.FileSystem.WriteAllBytes(Filename, Encoder.GetBytes(Header), False)
        
    End Sub

C#

public void CreateZipFile(string filename)
    {
        //Create the header of the Zip File 
        System.Text.ASCIIEncoding Encoder = new System.Text.ASCIIEncoding();
        string sHeader = "PK" + (char)5 + (char)6;
        sHeader = sHeader.PadRight(22, (char)0);
        //Convert to byte array
        byte[] baHeader = System.Text.Encoding.ASCII.GetBytes(sHeader);

        //Save File - Make sure your file ends with .zip!
        FileStream fs = File.Create(filename);
        fs.Write(baHeader, 0, baHeader.Length);
        fs.Flush();
        fs.Close();
        fs = null;
    } 

那么我们到底完成了什么?我们创建了一个空的 Zip 文件,这与在 Windows 的文件夹中右键单击并选择“**新建**”>“**压缩(zipped)文件夹**”是相同的。

现在我们有了创建空 *.zip 文件的函数,就可以将数据复制到文件中了。

您需要向您的 shell32.dll 文件添加一个引用,该文件位于您的 System32 文件夹中。

由于并非所有运行 Windows 的计算机设置都相同,因此这是查找 Windows 文件夹(包括驱动器号)的方法。

SET_Get_WinDir.jpg

现在我可以看到我的 Windows 文件夹在 C 盘,文件夹是 Windows。我现在知道我要找的文件在 C:\Windows\System32

在我们的 Visual Studio 项目中,我们需要为此文件添加一个引用,因此在解决方案资源管理器中右键单击您的项目,然后选择“添加引用”。

AddRef1.jpg

然后选择“浏览”,并找到文件。

AddRef2.jpg

如何在 VB.NET 和 C# 中将文件或文件夹复制到 *.zip 文件。

VB.NET

     Public Sub ZipFile(ByVal Input As String, ByVal Filename As String)
        Dim Shell As New Shell32.Shell

        'Create our Zip File
        CreateZipFile(Filename) 'Create a new .zip file

        'Copy the file or folder to it
        Shell.NameSpace(Filename).CopyHere(Input)

        'Wait until the File/Folder has finished writing to zip file...
        Do Until Shell.NameSpace(Filename).Items.Count = 
				Shell.NameSpace(Input).Items.Count
            System.Threading.Thread.Sleep(200)
            System.Diagnostics.Debug.Print("Waiting...")
        Loop
    End Sub

C#

public void ZipFile(string Input, string Filename)
    {
        Shell32.Shell Shell = new Shell32.Shell();
        
        //Create our Zip File
        CreateZipFile(Filename);

        //Copy the file or folder to it
        Shell.NameSpace(Filename).CopyHere(Input,0);
          
        //If you can write the code to wait for the code to finish, please let me know
        System.Threading.Thread.Sleep(2000);

        }
    }

结论

虽然这并不实用,因为您需要编写逻辑来处理现有的 Zip 文件,但写这篇文章很有趣,希望有人觉得它很有启发性。

© . All rights reserved.