2009-03-08 14 views
10

Quiero comprimir una carpeta usando la compresión NTFS en .NET. Encontré this post, pero no funciona. Lanza una excepción ("Parámetro no válido").Comprima una carpeta usando compresión NTFS en .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); 
    } 
} 

¿Alguien sabe cómo habilitar la compresión NTFS en una carpeta?

Respuesta

11

Usando P/Invoke es, en mi experiencia, por lo general más fácil que WMI. Creo que el siguiente debería funcionar:

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

Puesto que usted está tratando de establecer esto en un directorio, es probable que tenga que utilizar P/Invoke para llamar CreateFile usando FILE_FLAG_BACKUP_SEMANTICS para obtener el SafeFileHandle en el directorio.

Además, tenga en cuenta que establecer la compresión en un directorio en NTFS no comprime todos los contenidos, solo hace que los archivos nuevos aparezcan como comprimidos (lo mismo es cierto para el cifrado). Si desea comprimir todo el directorio, deberá recorrer todo el directorio y llamar a DeviceIoControl en cada archivo/carpeta.

0

No creo que exista una forma de establecer la compresión de carpetas en el marco .NET ya que los documentos (sección de comentarios) afirman que no se puede hacer a través de File.SetAttributes. Esto parece estar solo disponible en la API de Win32 usando la función DeviceIoControl. Todavía se puede hacer esto a través de .NET usando PInvoke.

Una vez familiarizado con PInvoke en general, consulte la referencia en pinvoke.net que explica cómo debe verse el signature para que esto suceda.

8

He probado el código y lo alt text!

  • Asegúrate de que funcione para ti con la interfaz gráfica de usuario. Tal vez el tamaño de la unidad de asignación sea demasiado grande para la compresión. O no tienes suficientes permisos.
  • Para su destino, utilice el formato de la siguiente manera: "c:/temp/testcomp" con barras inclinadas.

código 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

las nuevas barras hicieron el truco, gracias !! – decasteljau

+3

Este es un enfoque mucho más limpio que resolver P/Invocar, más importante aún, en realidad no funcionó a pesar de devolver un código de estado de éxito. Aunque el '. ManagementObject' .ctor es quisquilloso, utilicé este' string objPath = "Win32_Directory.Name =" + "'" + dir.FullName.Replace ("\\", @ "\\"). TrimEnd (' \ \ ') + "'"; 'para garantizar que el' ManagementObject' no arroje un parámetro inválido. –

+0

¿cómo se descomprime el directorio por cierto? –

1

Al crear el Win32_Directory.Name = ... cadena que necesitas las barras invertidas, así que por ejemplo la ruta C: \ Foo \ Bar se construiría como:

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

o utilizar el código de ejemplo:

cadena OBJPATH = "Win32_Directory.Name = \" C: \\\\ \\\\ Foo Bar \ "";

Aparentemente, la cadena se alimenta a un proceso que espera una forma de escape de la cadena de ruta de acceso.

0

Esta es una pequeña adaptación de Igal Serban respuesta. Me encontré con un problema sutil con el Name teniendo que estar en un formato muy específico.Así que agregué Replace("\\", @"\\").TrimEnd('\\')magia para normalizar la ruta primero, también limpié el código un poco.

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

Hay una manera mucho más simple, que estoy usando en Windows 8 de 64 bits, reescrito para VB.NET. Disfrutar.

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 

funciona muy bien para mí. Chagne. \ Root a \ pcname \ root si necesita hacerlo en otra computadora. Use con cuidado.

Cuestiones relacionadas