Como renomear arquivos e pastas em .rar .7z, .tar, .zip usando C #

12

Eu tenho um arquivo compactado .rar .7z, .tar e .zip e desejo renomear o nome do arquivo físico disponível no arquivo compactado acima, arquivado usando C #.

Eu tentei isso usando uma biblioteca sharpcompress, mas não consigo encontrar esse recurso para renomear o nome do arquivo ou da pasta nos arquivos .rar .7z, .tar e .zip.

Eu também tentei usar a biblioteca DotNetZip, mas seu único suporte.Zip Veja o que eu tentei usar a 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());
            }

        }

Mas, na verdade, o mesmo que acima, também quero para .7z, .rar e .tar, tentei muitas bibliotecas, mas ainda não obtive nenhuma solução precisa.

Por favor me ajude.

Nikunj Satasiya
fonte
Existe um var result = Path.ChangeExtension(myffile, ".jpg");-> docs.microsoft.com/en-us/dotnet/api/… #
panoskarajohn
Oi panoskarajohn, eu quero fazer isso no arquivo dentro do arquivo listado na pergunta, existe alguma solução que você possa sugerir?
Nikunj Satasiya
Sinto muito, não tenho uma solução limpa para isso, tenho certeza que você pode fazer the renameapós o Extract () como zip.
panoskarajohn
11
Sim, desejo renomear os arquivos dentro do arquivo compactado compactado sem extrair o arquivo compactado e o formato do arquivo compactado pode ser qualquer coisa como .rar .7z, .tar ou .zip.
Nikunj Satasiya
4
Na maioria dos formatos, se não todos, os nomes de arquivos e diretórios são codificados com um tamanho variável no arquivo binário resultante; portanto, você não pode simplesmente "corrigi-lo"; é necessário reconstruir algumas partes do arquivo. Bibliotecas padrão não fazem isso. Você precisará entrar em cada formato de arquivo e ver como pode fazê-lo. Tarefa difícil. Exemplo: stackoverflow.com/questions/32829839/…
Simon Mourier

Respostas:

3

Este é um aplicativo de console simples para renomear arquivos em .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
fonte
Obrigado, Binara, pela sua resposta, mas como posso ver na sua valiosa resposta, você está certo, podemos renomear um arquivo no arquivo zip como você mostrou na sua resposta, mas se meu arquivo for grande, então? ele abrirá o arquivo original, copiará todo o conteúdo e gravará novamente o mesmo conteúdo em outro arquivo e salvará o novo arquivo; acho que será um processo demorado. Você tem alguma outra solução, por favor?
Nikunj Satasiya 31/12/19
11
Tente Parallel.ForEach em vez de loop seqüencial. Eu mudei o código de acordo.
Binara Thambugala
Obrigado Binara, vou tentar esta solução para renomear o arquivo no arquivo .zip, mas ainda assim, há um problema, como quando modificarei qualquer arquivo no arquivo, ele comprimirá novamente todo o meu zip, então existe alguma solução para isso?
Nikunj Satasiya
3

Considere 7zipsharp:

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

O próprio 7zip suporta muitos formatos de arquivo (acredito que tudo o que você mencionou) e o 7zipsharp usa o 7zip real. Eu usei 7zipsharp apenas para arquivos .7z, mas aposto que funciona para outros.

Aqui está uma amostra de um teste que parece renomear um arquivo usando o método ModifyArchive, sugiro que você vá para a escola:

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

Aqui está o código simplificado um pouco. Observe que o teste compacta um arquivo 7z para seu teste; isso é imaterial, pode ser .txt, etc. Observe também que localiza o arquivo por índice no dicionário passado para o ModifyArchive. Consulte a documentação para obter esse índice a partir de um nome de arquivo (talvez você precise fazer um loop e 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
fonte
Oi FastAI, Obrigado pela sua resposta, mas eu também já experimentei essa biblioteca antes, mas geralmente quando modificamos qualquer arquivo dentro do arquivo, seja o conteúdo ou o nome, o arquivo está sendo compactado novamente. . Como você recebeu um exemplo de código na sua resposta, acho que você extraiu o arquivo primeiro usando 'ExtractArchive' e depois faz outras modificações, mas essa não é uma solução confiável. Você pode sugerir outra maneira alternativa pela qual a canônica é canônica? para que também possa melhorar o desempenho.
Nikunj Satasiya
11
@NikunjSatasiya - Desculpe voltar tão tarde. Não há como fazer isso sem reescrever o arquivo. Pense no que deve acontecer. Há um diretório no arquivo morto com os nomes dos arquivos e um índice para o conteúdo compactado. Esta não é uma entrada de comprimento fixo / acolchoada / onde você pode alterar o comprimento. Talvez você pudesse com um editor binário - mas as indicações de arquivos e seus dados compactados do 'diretório' seriam danificados. Talvez você possa alterar o nome do arquivo assim e manter o mesmo comprimento. Kludge sério, provavelmente não um recurso.
FastAl
11
E considere se o diretório de arquivos está compactado ou criptografado. Nenhuma mudança externa seria possível. Suponho que se o formato de arquivo .7z foi projetado desde o início para lidar com renomeações no local, e isso foi feito por um desenvolvedor do projeto, isso pode ser possível, mas ainda estamos muito longe disso. Eu sinto sua dor!
FastAl 29/01