C# 在.NET中使用NTFS压缩压缩文件夹

C# 在.NET中使用NTFS压缩压缩文件夹,c#,.net,windows,ntfs,C#,.net,Windows,Ntfs,我想在.NET中使用NTFS压缩来压缩文件夹。我找到了,但它不起作用。它抛出一个异常(“无效参数”) 有人知道如何在文件夹上启用NTFS压缩吗?我不相信有一种方法可以在.NET framework中设置文件夹压缩,因为文档(备注部分)声称这是无法通过的。这似乎仅在使用函数的Win32 API中可用。我们仍然可以通过.NET使用 一旦基本熟悉PInvoke,请查看网站上的参考资料,其中讨论了实现这一点所需的外观。我已经测试了代码,并且已经完成了测试 确保它适用于gui。也许分配单元的大小对于压缩

我想在.NET中使用NTFS压缩来压缩文件夹。我找到了,但它不起作用。它抛出一个异常(“无效参数”)


有人知道如何在文件夹上启用NTFS压缩吗?

我不相信有一种方法可以在.NET framework中设置文件夹压缩,因为文档(备注部分)声称这是无法通过的。这似乎仅在使用函数的Win32 API中可用。我们仍然可以通过.NET使用


一旦基本熟悉PInvoke,请查看网站上的参考资料,其中讨论了实现这一点所需的外观。

我已经测试了代码,并且已经完成了测试

  • 确保它适用于gui。也许分配单元的大小对于压缩来说太大了。或者您没有足够的权限
  • 对于您的目的地,请使用如下格式:“c:/temp/testcomp”和正斜杠
完整代码:

using System.IO;
using System.Management;

class Program
{
    static void Main(string[] args)
    {
        string destinationDir = "c:/temp/testcomp";
        DirectoryInfo directoryInfo = new DirectoryInfo(destinationDir);
        if ((directoryInfo.Attributes & FileAttributes.Compressed) != FileAttributes.Compressed)
        {
            string objPath = "Win32_Directory.Name=" + "\"" + destinationDir + "\"";
            using (ManagementObject dir = new ManagementObject(objPath))
            {
                ManagementBaseObject outParams = dir.InvokeMethod("Compress", null, null);
                uint ret = (uint)(outParams.Properties["ReturnValue"].Value);
            }
        }
     }
}

根据我的经验,使用p/Invoke通常比WMI更容易。我认为以下措施应该有效:

private const int FSCTL_SET_COMPRESSION = 0x9C040;
private const short COMPRESSION_FORMAT_DEFAULT = 1;

[DllImport("kernel32.dll", SetLastError = true)]
private static extern int DeviceIoControl(
    SafeFileHandle hDevice,
    int dwIoControlCode,
    ref short lpInBuffer,
    int nInBufferSize,
    IntPtr lpOutBuffer,
    int nOutBufferSize,
    ref int lpBytesReturned,
    IntPtr lpOverlapped);

public static bool EnableCompression(SafeFileHandle handle)
{
    int lpBytesReturned = 0;
    short lpInBuffer = COMPRESSION_FORMAT_DEFAULT;

    return DeviceIoControl(handle, FSCTL_SET_COMPRESSION,
        ref lpInBuffer, sizeof(short), IntPtr.Zero, 0,
        ref lpBytesReturned, IntPtr.Zero) != 0;
}
由于您正试图在目录上设置此项,因此可能需要使用p/Invoke调用using
FILE\u FLAG\u BACKUP\u SEMANTICS
来获取目录上的SafeFileHandle


另外,请注意,在NTFS中的目录上设置压缩不会压缩所有内容,它只会使新文件显示为压缩文件(加密也是如此)。如果要压缩整个目录,需要遍历整个目录,并在每个文件/文件夹上调用DeviceIoControl。

创建Win32_目录时。名称=。。。字符串需要将反斜杠加倍,因此,例如,路径C:\Foo\Bar将构建为:

Win32\u目录。Name=“C:\\Foo\\Bar”

或者使用您的示例代码:

字符串objPath=“Win32\u目录。名称=\”C:\\\\Foo\\\\Bar\”


显然,该字符串被馈送到某个进程,该进程需要路径字符串的转义形式。

这是对Igal Serban答案的轻微修改。我遇到了一个微妙的问题,
名称必须采用非常具体的格式。因此,我添加了一些
Replace(“\\”,@“\\”)
magic来首先规范化路径,我还清理了一些代码

var dir = new DirectoryInfo(_outputFolder);

if (!dir.Exists)
{
    dir.Create();
}

if ((dir.Attributes & FileAttributes.Compressed) == 0)
{
    try
    {
        // Enable compression for the output folder
        // (this will save a ton of disk space)

        string objPath = "Win32_Directory.Name=" + "'" + dir.FullName.Replace("\\", @"\\").TrimEnd('\\') + "'";

        using (ManagementObject obj = new ManagementObject(objPath))
        {
            using (obj.InvokeMethod("Compress", null, null))
            {
                // I don't really care about the return value, 
                // if we enabled it great but it can also be done manually
                // if really needed
            }
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Trace.WriteLine("Cannot enable compression for folder '" + dir.FullName + "': " + ex.Message, "WMI");
    }
}

有一种更简单的方法,我在Windows8中使用64位,为VB.NET重写。享受

    Dim Path as string = "c:\test"
    Dim strComputer As String = "."
    Dim objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Dim colFolders = objWMIService.ExecQuery("Select * from Win32_Directory where name = '" & Replace(path, "\", "\\") & "'")
    For Each objFolder In colFolders
        objFolder.Compress()
    Next

这对我很有用。Chagne。\root到\pcname\root,如果您需要在另一台计算机上执行此操作。小心使用。

这是一种比解析为p/Invoke更干净的方法,更重要的是,尽管返回了成功状态代码,但它实际上并不起作用。虽然
ManagementObject
.ctor很挑剔,但我使用了这个
string objPath=“Win32\u Directory.Name=“+””“+dir.FullName.Replace(“\\”,@“\\”).TrimEnd(“\\”)+”
以确保
ManagementObject
不会抛出无效参数。顺便说一句,如何解压缩目录?只说“未定义类型‘ManagementObject’”&“未定义类型‘ManagementBaseObject’”。还警告导入系统。管理不是nec。我的版本是VS2019
    Dim Path as string = "c:\test"
    Dim strComputer As String = "."
    Dim objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Dim colFolders = objWMIService.ExecQuery("Select * from Win32_Directory where name = '" & Replace(path, "\", "\\") & "'")
    For Each objFolder In colFolders
        objFolder.Compress()
    Next