2009-03-08 15 views
10

Voglio comprimere una cartella utilizzando la compressione NTFS in .NET. Ho trovato this post, ma non funziona. Genera un'eccezione ("Parametro non valido").Comprime una cartella utilizzando la compressione NTFS 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); 
    } 
} 

Qualcuno sa come attivare la compressione NTFS su una cartella?

risposta

11

Utilizzando P/Invoke è, nella mia esperienza, di solito più facile di WMI. Credo che il seguente dovrebbe funzionare:

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

Dal momento che si sta cercando di impostare questo su una directory, si avrà probabilmente bisogno di utilizzare P/Invoke per chiamare CreateFile utilizzando FILE_FLAG_BACKUP_SEMANTICS per ottenere il SafeFileHandle sulla directory.

Inoltre, si noti che l'impostazione della compressione su una directory in NTFS non comprime tutti i contenuti, ma visualizza solo i nuovi file come compressi (lo stesso vale per la crittografia). Se si desidera comprimere l'intera directory, è necessario percorrere l'intera directory e chiamare DeviceIoControl su ciascun file/cartella.

0

Non credo che ci sia un modo per impostare la compressione delle cartelle nel framework .NET come i documenti (sezione commenti) affermano che non può essere fatto attraverso File.SetAttributes. Questo sembra essere disponibile solo nell'API Win32 utilizzando la funzione DeviceIoControl. Si può ancora farlo attraverso .NET usando PInvoke.

Una volta acquisita familiarità con PInvoke in generale, consultare il riferimento allo pinvoke.net in cui viene illustrato come deve essere il signature per consentire che ciò accada.

8

Ho provato il codice e lo alt text!

  • Assicurati che funzioni per te con la GUI. Forse la dimensione dell'unità di allocazione è troppo grande per la compressione. O non hai permessi sufficienti.
  • Per la destinazione utilizzare il formato in questo modo: "c:/temp/testcomp" con barre in avanti.

codice completo:

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

gli slash di foward hanno fatto il trucco, grazie !! – decasteljau

+3

Questo è un approccio molto più pulito rispetto alla risoluzione su P/Invoke, ancora più importante, in effetti non ha funzionato nonostante abbia restituito un codice di stato di successo. Sebbene 'ManagementObject' .ctor sia schizzinoso, ho usato questo' string objPath = "Win32_Directory.Name =" + "'" + dir.FullName.Replace ("\\", @ "\\"). TrimEnd (' \ \ ') + "'"; 'per garantire che il' ManagementObject' non getti parametri non validi. –

+0

come si decomprime la directory btw? –

1

Quando si crea il Win32_Directory.Name = ... stringa è necessario fare doppio le barre inverse, così per esempio il percorso C: \ Foo \ bar sarebbe stato costruito come:

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

o utilizzare il codice di esempio:

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

Apparentemente la stringa viene inviata ad un processo che si aspetta una forma di escape della stringa di percorso.

0

Questo è un leggero adattamento della risposta di Igal Serban. Ho avuto un piccolo problema con il Name che doveva essere in un formato molto specifico.Così ho aggiunto alcuni Replace("\\", @"\\").TrimEnd('\\')magic per normalizzare prima il percorso, ho anche ripulito un po 'il codice.

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

C'è un modo molto più semplice, che sto usando in Windows 8 64-bit, riscritto per VB.NET. Godere.

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 

funziona perfettamente per me. Chagne. \ Root a \ pcname \ root se è necessario farlo su un altro computer. Usare con cura.

Problemi correlati