una renombrar que pasar para otra nombres nombre masivamente masiva macro forma copie copiar comprimir como carpeta cambiar archivos archivo vba vb6 zip compression shell32
https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile.createfromdirectory(v=vs.110).aspx

vba - que - macro para renombrar archivos



Cómo comprimir contenido de carpeta en 1 instrucción en Windows? (2)

Automatizar los objetos de Shell realmente no es un enfoque viable como ya has descubierto. Sin embargo, el Explorador Shell realmente no expone esta capacidad de ninguna otra manera, al menos no antes de Windows Vista y luego, de ninguna manera, se usa fácilmente desde los programas VB6 o las macros VBA.

Su mejor opción es una biblioteca ActiveX de un tercero, pero tenga cuidado con los hosts de VBA de 64 bits donde necesitará una versión de 64 bits de dicha biblioteca.

Otra opción es adquirir una copia posterior de zlibwapi.dll y usar algún código de envoltura VB6 con ella. Esta es también una solución de 32 bits.

Eso es lo que Zipper y ZipWriter, Zipping de los programas de VB . Teniendo en cuenta sus requisitos (que por alguna razón incluye el miedo al control del temporizador) puede utilizar la clase ZipperSync síncrona. Ver la publicación # 4 allí. Ese código incluye un simple AddFolderToZipperSync la lógica para agregar una carpeta en lugar de solo un archivo.

La desventaja de la clase sincrónica es que una gran operación de archivo congela la IU de su programa hasta que se complete. Si no lo desea, use Zipper UserControl en su lugar.

También puede tomar las ideas de eso para escribir su propia clase contenedora.

Estoy intentando comprimir una carpeta que contiene subcarpetas y elementos, usando el comando CopyHere shell de Windows:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb787866(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/windows/desktop/ ms723207 (v = vs.85) .aspx

Actualización: tenga en cuenta que prefiere una solución nativa, esto es para una herramienta de Excel VBA distribuida, por lo que agrupar archivos de terceros no es ideal. Y, necesita compresión sincrónica .

Puedo agregar fácilmente una carpeta y su contenido al zip:

oShell.Namespace(sZipPath).CopyHere "C:/My Folder"

Entonces sabemos que CopyHere puede procesar múltiples objetos dentro de una carpeta en 1 declaración.

El problema es que el comando anterior coloca la carpeta contenedora en la raíz del archivo zip y su contenido dentro de ella. Pero no quiero la carpeta que contiene, solo su contenido.

El documento menciona un comodín (opción 128), pero cuando uso un comodín, recibo un error:

oShell.Namespace(sZipPath).CopyHere "C:/My Folder/*"

El nombre de archivo que especificó no es válido o demasiado largo.

Tal vez haya una forma de usar mi 1er comando arriba, y luego mover los elementos en el zip a la raíz del zip.

Sería aceptable recorrer cada elemento en la carpeta de origen, agregando uno a la vez al zip. Pero, debido a que CopyHere es asíncrono, cada CopyHere subsiguiente falla si el CopyHere anterior no está terminado. Ninguna de las correcciones funciona para este problema:

  • No se puede comparar el número de elementos en la carpeta de origen y el zip de destino, ya que si el archivo zip contiene una carpeta, eso solo cuenta como 1 artículo (los artículos que contiene no se cuentan. Https://stackoverflow.com/a/16603850/209942

  • Esperar un momento entre cada elemento funciona, pero un temporizador es inaceptable: es arbitrario. No puedo adivinar de antemano el tamaño o el tiempo de compresión de cada objeto.

  • Verifico si el zip está bloqueado para el acceso. Si bloqueo mi ciclo hasta que el archivo no esté bloqueado, sigo teniendo un error de acceso al archivo. https://stackoverflow.com/a/6666663/209942

Function FileIsOpen(sPathname As String) As Boolean '' true if file is open Dim lFileNum As Long lFileNum = FreeFile Dim lErr As Long On Error Resume Next Open sPathname For Binary Access Read Write Lock Read Write As #lFileNum lErr = Err Close #lFileNum On Error GoTo 0 FileIsOpen = (lErr <> 0) End Function

Actualización: VBA puede llamar comandos de shell de forma síncrona (en lugar de crear un objeto shell32.shell en VBA), por lo que si CopyHere funciona en línea de comandos o PowerShell, esa podría ser la solución. Investigando ...


Solución:

Windows contiene otra utilidad de compresión nativa: CreateFromDirectory en un indicador de PowerShell.

https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile.createfromdirectory(v=vs.110).aspx

https://blogs.technet.microsoft.com/heyscriptingguy/2015/03/09/use-powershell-to-create-zip-archive-of-folder/

Esto requiere .Net 4.0 o posterior:

> Add-Type -AssemblyName System.IO.Compression > $src = "C:/Users/v1453957/documents/Experiment/rezip/aFolder" > $zip="C:/Users/v1453957/Documents/Experiment/rezip/my.zip" > [io.compression.zipfile]::CreateFromDirectory($src, $zip)

Tenga en cuenta que es posible que deba proporcionar los nombres completos de las rutas-- el directorio activo no estaba implícito en mi máquina.

La compresión anterior es síncrona en el indicador de PowerShell, como lo solicita el OP.

El siguiente paso es ejecutar sincrónicamente desde VBA. La solución es el método .Run en Windows Script Host Object Model . En VBA, establezca una referencia a eso, y haga lo siguiente, estableciendo el 3er parámetro del comando bWaitOnReturn , bWaitOnReturn en True :

Function SynchronousShell(sCmd As String)As Long Dim oWSH As New IWshRuntimeLibrary.WshShell ShellSynch = oWSH.Run(sCmd, 3, True) Set oWSH = Nothing End Function

Ahora llame a SynchronousShell y pase todo el script de compresión.

Creo que la única forma de que este proceso funcione es si CreateFromDirectory se ejecuta en la misma sesión que Add-Type .

Entonces, debemos pasar todo el asunto como 1 cadena. Es decir, cargue los 4 comandos en una sola variable sCmd , de modo que Add-Type permanezca asociado con el CreateFromDirectory posterior. En la sintaxis de PowerShell, puede separarlos con ;

https://thomas.vanhoutte.be/miniblog/execute-multiple-powershell-commands-on-one-line/

Además, querrá usar comillas simples en lugar de comillas dobles, de lo contrario las comillas dobles alrededor de las cadenas se eliminarán cuando los comandos en cadena margarita se pasen a powershell.exe

https://.com/a/39801732/209942

sCmd = "ps4 Add-Type -AssemblyName System.IO.Compression; $src = ''C:/Users/v1453957/documents/Experiment/rezip/aFolder''; $zip=''C:/Users/v1453957/Documents/Experiment/rezip/my.zip''; [io.compression.zipfile]::CreateFromDirectory($src, $zip)"

Resuelto Lo anterior constituye la solución completa.

Información adicional : los comentarios adicionales a continuación son para circunstancias especiales:

Entornos .Net de varias versiones

Si un .NET <4.0 es el entorno activo en su SO, entonces System.IO.Compression no existe-- Add-Type comando Add-Type fallará. Pero si su máquina tiene los ensamblados .NET 4 disponibles, aún puede hacer esto:

  • Cree un archivo por lotes que ejecute PowerShell con .Net 4. Consulte https://.com/a/31279372.

  • En su comando Add-Type anterior, use la ruta exacta al conjunto de compresión .Net 4. En mi Win Server 2008:

Add-Type -Path "C:/Windows/Microsoft.NET/assembly/GAC_MSIL/System.IO.Compression.FileSystem/v4.0_4.0.0.0__b77a5c561934e089/System.IO.Compression.FileSystem.dll"

Portabilidad

Resulta que, en mi máquina, puedo copiar el dll de compresión a cualquier carpeta y hacer llamadas a la copia y funciona:

Add-Type -Path "C:/MyFunnyFolder/System.IO.Compression.FileSystem.dll"

No sé lo que se requiere para garantizar que esto funcione; podría requerir que los archivos .Net 4.0 o 2.0 completos se ubiquen en sus directorios esperados. Supongo que el dll hace llamadas a otros ensamblados .Net. Quizás tuvimos suerte con esto :)

Límite de caracteres

Dependiendo de la profundidad de nuestros caminos y nombres de archivo, el conteo de caracteres puede ser una preocupación. PowerShell puede tener un límite de 260 caracteres (no estoy seguro).

https://support.microsoft.com/en-us/kb/830473

https://social.technet.microsoft.com/Forums/windowsserver/en-US/f895d766-5ffb-483f-97bc-19ac446da9f8/powershell-command-size-limit?forum=winserverpowershell

Como .Run pasa por el shell de Windows, también debe preocuparse por el límite de caracteres, pero a 8k +, es un poco más amplio: https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553 https://.com/a/3205048/209942

El siguiente sitio ofrece un método de 24k + caracteres, pero aún no lo he estudiado: http://itproctology.blogspot.com/2013/06/handling-freakishly-long-strings-from.html

Como mínimo, ya que podemos poner el dll donde queramos, podemos ponerlo en una carpeta cerca de C: root - manteniendo nuestra cuenta de caracteres hacia abajo.

Actualización: esta publicación muestra cómo podemos poner todo en un script-file y llamarlo con ps4.cmd. Esta puede ser mi respuesta preferida:

./ps4.cmd GC ./zipper.ps1 | IEX

- dependiendo de la respuesta aquí .

Copia aquí:

Re la pregunta: ¿Puede el comando CopyHere ejecutarse en la línea de comandos?

CopyHere se puede ejecutar directamente en el indicador de PowerShell (código a continuación). Sin embargo, incluso en powershell, es asincrónico: el control vuelve al indicador de PowerShell antes de que el proceso finalice. Por lo tanto, no hay solución para el OP. Así es como se hace:

> $shellapp=new-object -com shell.application > $zippath="test.zip" > $zipobj=$shellapp.namespace((Get-Location).Path + "/$zippath") > $srcpath="src" > $srcobj=$shellapp.namespace((Get-Location).Path + "/$srcpath") > $zipobj.Copyhere($srcobj.items())