Jak zmienić nazwę plików i folderów w .rar .7z, .tar, .zip przy użyciu C #

12

Mam skompresowany plik .rar .7z, .tar i .zip i chcę zmienić nazwę fizycznej nazwy pliku dostępnej w powyższym skompresowanym archiwizowanym przy użyciu C #.

Próbowałem tego przy użyciu biblioteki sharpcompress, ale nie mogę znaleźć takiej funkcji zmiany nazwy pliku lub folderu w plikach .rar .7z, .tar i .zip.

Próbowałem również użyć biblioteki DotNetZip, ale jest to jedyne wsparcie. Zobacz, co próbowałem przy użyciu biblioteki 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());
            }

        }

Ale właściwie to samo co powyżej, chcę również dla .7z, .rar i .tar, próbowałem wielu bibliotek, ale wciąż nie znalazłem żadnego dokładnego rozwiązania.

Proszę pomóż mi.

Nikunj Satasiya
źródło
Jest var result = Path.ChangeExtension(myffile, ".jpg");-> docs.microsoft.com/en-us/dotnet/api/…
panoskarajohn
Cześć panoskarajohn, chcę to zrobić w archiwum wymienionym w pytaniu, czy istnieje jakieś rozwiązanie?
Nikunj Satasiya
Przykro mi, ale nie mam na to czystego rozwiązania, jestem pewien, że możesz to zrobić the renamepo Extract () as zip.
panoskarajohn
1
Tak, chcę zmienić nazwę plików w spakowanym archiwum bez rozpakowywania archiwum i formatem archiwum może być dowolny .rar .7z, .tar lub .zip.
Nikunj Satasiya
4
W większości formatów, jeśli nie wszystkie, nazwy plików i katalogów są kodowane zmiennym rozmiarem w wynikowym pliku binarnym, więc nie można go po prostu „załatać”, trzeba zrekonstruować niektóre części pliku. Biblioteki standardowe tego nie robią. Musisz przejść do każdego formatu archiwum i zobaczyć, jak to zrobić. Trudne zadanie. Przykład: stackoverflow.com/questions/32829839/…
Simon Mourier

Odpowiedzi:

3

Jest to prosta aplikacja konsoli do zmiany nazw plików w .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
źródło
Dzięki, Binara, za twoją odpowiedź, ale jak widzę w twojej cennej odpowiedzi masz rację, możemy zmienić nazwę pliku w archiwum zip, jak pokazałeś w odpowiedzi, ale jeśli mój plik jest duży? otworzy oryginalny plik, skopiuje z niego całą zawartość i zapisze tę samą zawartość w innym pliku i zapisze nowy plik, myślę, że będzie to czasochłonne. Czy masz jakieś inne rozwiązanie?
Nikunj Satasiya
1
Wypróbuj Parallel.ForEach zamiast Pętli sekwencyjnej. Odpowiednio zmieniłem kod.
Binara Thambugala
Dzięki Binara, wypróbuję to rozwiązanie, aby zmienić nazwę pliku w archiwum .zip, ale nadal istnieje jeden problem, na przykład kiedy zmodyfikuję dowolny plik w archiwum, a następnie ponownie skompresuje cały plik zip, więc czy jest na to jakieś rozwiązanie?
Nikunj Satasiya
3

Rozważ 7zipsharp:

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

Sam 7zip obsługuje wiele formatów archiwów (uważam, że wszystko, o czym wspomniałeś), a 7zipsharp używa prawdziwego 7zipa. Użyłem 7zipsharp tylko dla plików .7z, ale założę się, że działa dla innych.

Oto próbka testu, który wydaje się zmieniać nazwę pliku przy użyciu metody ModifyArchive, sugeruję pójście do szkoły:

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

Oto trochę uproszczony kod. Zauważ, że test kompresuje plik 7z do swojego testu; to nie ma znaczenia, może to być .txt itp. Zauważ też, że znajduje plik według indeksu w słowniku przekazanym do ModifyArchive. Zapoznaj się z dokumentacją, jak uzyskać ten indeks z nazwy pliku (być może trzeba zapętlić i porównać).

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
źródło
Cześć, FastAI, dziękuję za odpowiedź, ale wypróbowałem już tę bibliotekę wcześniej, ale ogólnie, gdy modyfikujemy dowolny plik w archiwum, zarówno jego zawartość, jak i nazwę, archiwum jest ponownie kompresowane, więc jego ponowne skompresowanie zajmuje dużo czasu, jeśli archiwum jest duże . Ponieważ w odpowiedzi podano przykładowy kod, myślę, że najpierw wyodrębniłeś archiwum za pomocą „ExtractArchive”, a następnie dokonałeś dalszych modyfikacji, ale nie jest to wiarygodne rozwiązanie. Czy możesz zasugerować inny alternatywny sposób, w jaki czarownica jest kanoniczna? więc może również poprawić wydajność. również.
Nikunj Satasiya
1
@NikunjSatasiya - Przepraszam, że wróciłem tak późno. Nie można tego zrobić bez ponownego zapisywania archiwum. Pomyśl o tym, co musi się stać. W pliku archiwum znajduje się katalog z nazwami plików oraz indeks skompresowanej zawartości. Nie jest to wpis „wyściełany” / o stałej długości, w którym można zmienić długość. Być może mógłbyś to zrobić za pomocą edytora binarnego - ale wtedy wkleiłyby się oznaczenia plików i ich skompresowanych danych z „katalogu”. Może mógłbyś zmienić taką nazwę pliku i zachować tę samą długość. Poważna kludge, mało prawdopodobne.
FastAl
1
A następnie zastanów się, czy katalog plików jest skompresowany czy zaszyfrowany. Żadne zmiany z zewnątrz nie byłyby możliwe. Podejrzewam, że jeśli format pliku .7z od samego początku został zaprojektowany do obsługi lokalnych nazw, a to zostało zrobione przez programistę w projekcie, może to być możliwe, ale jesteśmy daleko od tego. Czuję twój ból!
FastAl