Cómo cambiar el nombre de archivos y carpetas en .rar .7z, .tar, .zip usando C #

12

Tengo un archivo comprimido .rar .7z, .tar y .zip y quiero cambiar el nombre del archivo físico disponible en el archivo comprimido anterior usando C #.

He intentado esto usando una biblioteca sharpcompress pero no puedo encontrar una función para cambiar el nombre del archivo o carpeta dentro de los archivos .rar .7z, .tar y .zip.

También he intentado usar la biblioteca DotNetZip pero es su único soporte. Vea lo que he intentado usando la biblioteca DotNetZip.

private static void RenameZipEntries(string file)
        {
            try
            {
                int renameCount = 0;
                using (ZipFile zip2 = ZipFile.Read(file))
                {

                    foreach (ZipEntry e in zip2.ToList())
                    {
                        if (!e.IsDirectory)
                        {
                            if (e.FileName.EndsWith(".txt"))
                            {
                                var newname = e.FileName.Split('.')[0] + "_new." + e.FileName.Split('.')[1];
                                e.FileName = newname;
                                e.Comment = "renamed";
                                zip2.Save();
                                renameCount++;
                            }
                        }
                    }
                    zip2.Comment = String.Format("This archive has been modified. {0} files have been renamed.", renameCount);
                    zip2.Save();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

Pero en realidad lo mismo que el anterior también quiero para .7z, .rar y .tar, probé muchas bibliotecas pero aún no obtuve ninguna solución precisa.

Por favor, ayúdame.

Nikunj Satasiya
fuente
Hay un var result = Path.ChangeExtension(myffile, ".jpg");-> docs.microsoft.com/en-us/dotnet/api/…
panoskarajohn
Hola panoskarajohn, quiero hacer esto en el archivo dentro del archivo que figura en la pregunta, ¿hay alguna solución que pueda sugerir?
Nikunj Satasiya
Lo siento, no tengo una solución limpia para esto, estoy seguro de que puede hacerlo the renamedespués de Extract () como zip.
panoskarajohn
1
Sí, quiero cambiar el nombre de los archivos dentro del archivo comprimido sin extraer el archivo y el formato del archivo puede ser cualquier cosa .rar .7z, .tar o .zip.
Nikunj Satasiya
44
En la mayoría de los formatos, si no todos, los nombres de archivo y directorio están codificados con un tamaño variable en el archivo binario resultante, por lo que no puede simplemente "parchearlo", debe reconstruir algunas partes del archivo. Las bibliotecas estándar no hacen eso. Tendrá que acceder a cada formato de archivo y ver cómo puede hacerlo. Tarea difícil. Ejemplo: stackoverflow.com/questions/32829839/…
Simon Mourier

Respuestas:

3

Esta es una aplicación de consola simple para renombrar archivos en .zip

using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;

namespace Renamer
{
    class Program
    {
        static void Main(string[] args)
        {
            using var archive = new ZipArchive(File.Open(@"<Your File>.zip", FileMode.Open, FileAccess.ReadWrite), ZipArchiveMode.Update);
            var entries = archive.Entries.ToArray();

            //foreach (ZipArchiveEntry entry in entries)
            //{
            //    //If ZipArchiveEntry is a directory it will have its FullName property ending with "/" (e.g. "some_dir/") 
            //    //and its Name property will be empty string ("").
            //    if (!string.IsNullOrEmpty(entry.Name))
            //    {
            //        var newEntry = archive.CreateEntry($"{entry.FullName.Replace(entry.Name, $"{RandomString(10, false)}{Path.GetExtension(entry.Name)}")}");
            //        using (var a = entry.Open())
            //        using (var b = newEntry.Open())
            //            a.CopyTo(b);
            //        entry.Delete();
            //    }
            //}

            Parallel.ForEach(entries, entry =>
            {
                //If ZipArchiveEntry is a directory it will have its FullName property ending with "/" (e.g. "some_dir/") 
                //and its Name property will be empty string ("").
                if (!string.IsNullOrEmpty(entry.Name))
                {
                    ZipArchiveEntry newEntry = archive.CreateEntry($"{entry.FullName.Replace(entry.Name, $"{RandomString(10, false)}{Path.GetExtension(entry.Name)}")}");
                    using (var a = entry.Open())
                    using (var b = newEntry.Open())
                        a.CopyTo(b);
                    entry.Delete();
                }
            });
        }

        //To Generate random name for the file
        public static string RandomString(int size, bool lowerCase)
        {
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            char ch;
            for (int i = 0; i < size; i++)
            {
                ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
                builder.Append(ch);
            }
            if (lowerCase)
                return builder.ToString().ToLower();
            return builder.ToString();
        }
    }
}
Binara Thambugala
fuente
Gracias, Binara, por tu respuesta, pero como puedo ver en tu valiosa respuesta, tienes razón, podemos cambiar el nombre de un archivo en el archivo zip como mostraste en tu respuesta, pero si mi archivo es grande, ¿entonces? abrirá el archivo original, copiará todo el contenido de eso y volverá a escribir el mismo contenido en otro archivo y guardará el nuevo archivo, creo que será un proceso lento. ¿Tienes alguna otra solución por favor?
Nikunj Satasiya
1
Pruebe Parallel.ForEach en lugar de Sequential loop. He cambiado el código en consecuencia.
Binara Thambugala
Gracias Binara, intentaré esta solución para cambiar el nombre del archivo dentro del archivo .zip, pero aún así, hay un problema como cuando modifique cualquier archivo dentro del archivo y luego volverá a comprimir todo mi zip, ¿hay alguna solución para eso?
Nikunj Satasiya
3

Considere 7zipsharp:

https://www.nuget.org/packages/SevenZipSharp.Net45/

7zip en sí es compatible con muchos formatos de archivo (creo que todo lo que mencionó) y 7zipsharp usa el 7zip real. He usado 7zipsharp solo para archivos .7z pero apuesto a que funciona para otros.

Aquí hay una muestra de una prueba que parece cambiar el nombre de un archivo usando el método ModifyArchive, te sugiero que vayas a la escuela:

https://github.com/squid-box/SevenZipSharp/blob/f2bee350e997b0f4b1258dff520f36409198f006/SevenZip.Tests/SevenZipCompressorTests.cs

Aquí está el código simplificado un poco. Tenga en cuenta que la prueba comprime un archivo 7z para su prueba; eso es irrelevante, podría ser .txt, etc. También tenga en cuenta que encuentra el archivo por índice en el diccionario pasado a ModifyArchive. Consulte la documentación sobre cómo obtener ese índice de un nombre de archivo (tal vez tenga que hacer un bucle y comparar).

var compressor = new SevenZipCompressor( ... snip ...);

compressor.CompressFiles("tmp.7z", @"Testdata\7z_LZMA2.7z");

compressor.ModifyArchive("tmp.7z", new Dictionary<int, string> { { 0, "renamed.7z" }});

using (var extractor = new SevenZipExtractor("tmp.7z"))
{
    Assert.AreEqual(1, extractor.FilesCount);
    extractor.ExtractArchive(OutputDirectory);
}

Assert.IsTrue(File.Exists(Path.Combine(OutputDirectory, "renamed.7z")));
Assert.IsFalse(File.Exists(Path.Combine(OutputDirectory, "7z_LZMA2.7z")));
FastAl
fuente
Hola FastAI, gracias por su respuesta, pero también he probado esta biblioteca antes, pero generalmente cuando modificamos cualquier archivo dentro del archivo, ya sea su contenido o nombre, el archivo se está volviendo a comprimir, por lo que lleva tiempo volver a comprimirlo si el archivo es grande . Como se le da un código de muestra en su respuesta, creo que primero ha extraído el archivo usando 'ExtractArchive' y luego realiza más modificaciones, pero esta no es una solución confiable. ¿Puede sugerir alguna otra forma alternativa de bruja canónica? por lo que también puede mejorar el rendimiento.
Nikunj Satasiya
1
@NikunjSatasiya - Lamento volver tan tarde. No hay forma de hacerlo sin volver a escribir el archivo. Piensa en lo que debe pasar. Hay un directorio en el archivo con los nombres de archivo y un índice del contenido comprimido. Esta no es una entrada 'rellenada' / longitud fija donde puede cambiar la longitud. Quizás podría hacerlo con un editor binario, pero luego se atornillarían las indicaciones de los archivos y sus datos comprimidos del 'directorio'. Tal vez podría cambiar el nombre de archivo así y mantener la misma longitud. Kludge serio, no es una característica probable.
FastAl
1
Y luego considere si el directorio de archivos está comprimido o encriptado. Ningún cambio desde el exterior sería posible. Supongo que si el formato de archivo .7z se diseñó desde el principio para manejar los cambios de nombre en el lugar, y esto fue hecho por un desarrollador en el proyecto, esto podría ser posible, pero estamos muy lejos de eso. ¡Siento tu dolor!
FastAl