2009-03-08 7 views
10

Ich möchte einen Ordner mit NTFS-Komprimierung in .NET komprimieren. Ich habe this post gefunden, aber es funktioniert nicht. Es löst eine Ausnahme aus ("Ungültiger Parameter").Komprimieren Sie einen Ordner mit NTFS-Komprimierung in .NET

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); 
    } 
} 

Jeder weiß, wie man NTFS-Kompression auf einem Ordner aktiviert?

Antwort

11

Mit P/Invoke ist, in meiner Erfahrung, in der Regel einfacher als WMI. Ich glaube, die folgenden sollte funktionieren:

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; 
} 

Da Sie versuchen, diese auf einem Verzeichnis gesetzt, werden Sie wahrscheinlich P/Invoke verwenden müssen CreateFile anrufen FILE_FLAG_BACKUP_SEMANTICS mit dem Safefilehandle auf das Verzeichnis zu erhalten.

Beachten Sie auch, dass die Komprimierung eines Verzeichnisses in NTFS nicht den gesamten Inhalt komprimiert, sondern nur neue Dateien als komprimiert anzeigt (dasselbe gilt für die Verschlüsselung). Wenn Sie das gesamte Verzeichnis komprimieren möchten, müssen Sie das gesamte Verzeichnis durchsuchen und DeviceIoControl für jede Datei/jeden Ordner aufrufen.

0

Ich glaube nicht, dass es eine Möglichkeit gibt, Ordnerkomprimierung im .NET-Framework festzulegen, da die Dokumentation (Anmerkung) behauptet, sie könne nicht über File.SetAttributes ausgeführt werden. Dies scheint nur in der Win32-API mit der Funktion DeviceIoControl Funktion verfügbar. Man kann dies immer noch über .NET tun, indem man PInvoke verwendet.

Sobald Sie mit PInvoke im Allgemeinen vertraut sind, sehen Sie sich die Referenz unter pinvoke.net an, in der erläutert wird, wie die signature aussehen muss, um dies zu ermöglichen.

8

Ich habe den Code getestet und es alt text!

  • Stellen Sie sicher, dass es für Sie mit der GUI funktioniert. Möglicherweise ist die Größe der Zuordnungseinheit zu groß für die Komprimierung. Oder Sie haben keine ausreichenden Berechtigungen.
  • Verwenden Sie für Ihr Zielformat wie folgt: "c:/temp/testcomp" mit Schrägstrichen.

Voll Code:

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); 
      } 
     } 
    } 
} 
+2

die foward Schrägstriche haben den Trick, danke !! – decasteljau

+3

Dies ist ein viel sauberer Ansatz als P/Invoke zu lösen, wichtiger noch, es hat trotz der Rückgabe eines Erfolgsstatuscodes nicht funktioniert. Obwohl das 'ManagementObject' .ctor wählerisch ist, habe ich diese 'string objPath =" Win32_Directory.Name = "+"' "+ dir.FullName.Replace (" \\ ", @" \\ ") verwendet. TrimEnd ('\ \ ') + "'"; 'um sicherzustellen, dass das' ManagementObject' keinen ungültigen Parameter auslöst. –

+0

Wie dekomprimiere ich das Verzeichnis BTW? –

1

Wenn die Win32_Directory.Name Erstellen = ... Zeichenfolge, die Sie brauchen, um die Schrägstriche verdoppeln, so zum Beispiel der Pfad C: \ Foo \ Bar würde sich wie gebaut werden:

Win32_Directory.Name =“ C: \\ Foo \\ Bar“,

oder mit Ihrem Beispielcode:

String objPath = "Win32_Directory.Name = \" C: \\\\ Foo \\\\ Bar "";

Anscheinend wird die Zeichenfolge an einen Prozess übergeben, der eine maskierte Form der Pfadzeichenfolge erwartet.

0

Dies ist eine leichte Anpassung der Igal Serban Antwort. Ich stieß auf ein subtiles Problem mit dem Name, das in einem sehr spezifischen Format sein muss.Also fügte ich etwas Replace("\\", @"\\").TrimEnd('\\')magisch hinzu, um den Pfad zuerst zu normalisieren, ich räumte auch den Code etwas auf.

0

Es gibt einen viel einfacheren Weg, den ich in Windows 8 64-Bit verwende, für VB.NET umgeschrieben. Genießen.

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 

funktioniert gut für mich. Chagne. \ Root zu \ pcname \ root, wenn Sie es auf einem anderen Computer tun müssen. Verwenden Sie vorsichtig.

Verwandte Themen