Как переименовать файлы и папки в .rar .7z, .tar, .zip, используя C #

12

У меня есть сжатый файл .rar .7z, .tar и .zip, и я хочу переименовать физическое имя файла, имеющееся в архиве выше, с использованием C #.

Я пробовал это с помощью библиотеки sharpcompress, но я не могу найти такую ​​функцию для переименования файла или имени папки в файле .rar .7z, .tar и .zip.

Я также пытался использовать библиотеку DotNetZip, но она единственная поддержка. Zip посмотреть, что я пытался с помощью библиотеки 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());
            }

        }

Но на самом деле то же самое, что и выше, я также хочу для .7z, .rar и .tar, я перепробовал много библиотек, но все же я не получил никакого точного решения.

Пожалуйста, помогите мне.

Никунь Сатасия
источник
Существует var result = Path.ChangeExtension(myffile, ".jpg");-> docs.microsoft.com/en-us/dotnet/api/...
panoskarajohn
Привет panoskarajohn, я хочу сделать это в файле в архиве, указанном в вопросе, есть ли какое-нибудь решение, которое ты можешь предложить?
Никунь Сатасия
Извините, у меня нет чистого решения для этого, я уверен, что вы можете сделать the renameпосле Extract () как zip.
Panoskarajohn
1
Да, я хочу переименовать файлы внутри zip-архива без распаковки архива, а формат файла архива может быть любым .rar .7z, .tar или .zip.
Никунь Сатасия
4
В большинстве форматов, если не все, имена файлов и каталогов закодированы с переменным размером в результирующем двоичном файле, поэтому вы не можете просто «пропатчить» его, вам необходимо восстановить некоторые части файла. Стандартные библиотеки этого не делают. Вам нужно будет войти в каждый формат архива и посмотреть, как вы можете это сделать. Сложное задание. Пример: stackoverflow.com/questions/32829839/…
Саймон Мурье

Ответы:

3

Это простое консольное приложение для переименования файлов в .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();
        }
    }
}
Бинара Тамбугала
источник
Спасибо, Бинара, за твой ответ, но, как я вижу в твоем ценном ответе, ты прав, мы можем переименовать файл в zip-архиве, как ты показал в своем ответе, но если мой файл большой, тогда? он откроет исходный файл, скопирует весь контент из него и запишет тот же контент в другой файл и сохранит новый файл, я думаю, это будет трудоемкий процесс. У вас есть другое решение, пожалуйста?
Никунь Сатасия
1
Попробуйте Parallel.ForEach вместо последовательного цикла. Я изменил код соответственно.
Бинара Тамбугала
Спасибо, Бинара, я попробую это решение для переименования файла в архиве .zip, но, тем не менее, есть одна проблема, например, когда я изменю любой файл в архиве, тогда он будет повторно сжать весь мой zip, так есть ли какое-то решение для этого?
Никунь Сатасия
3

Рассмотрим 7zipsharp:

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

Сам 7zip поддерживает множество форматов архивов (я полагаю, все, что вы упомянули), а 7zipsharp использует настоящий 7zip. Я использовал 7zipsharp только для файлов .7z, но держу пари, что это работает для других.

Вот пример теста, который, кажется, переименовывает файл, используя метод ModifyArchive, я предлагаю вам пойти в школу в нем:

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

Вот код немного упростил. Обратите внимание, что тест сжимает файл 7z для своего теста; это неважно, это может быть .txt и т. д. Также обратите внимание, что он находит файл по индексу в словаре, переданном в ModifyArchive. Консультируйтесь с документацией для того, как получить тот индекс от имени файла (возможно, вам придется зацикливаться и сравнивать).

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
источник
Привет, FastAI, Спасибо за твой ответ, но я тоже пробовал эту библиотеку раньше, но обычно, когда мы изменяем любой файл внутри архива, будь то содержимое или имя, архив повторно сжимается, поэтому для повторного сжатия у него требуется время, если архив большой , Поскольку вам дается пример кода в вашем ответе, то я думаю, что вы сначала распаковали архив с помощью «ExtractArchive», а затем продолжаете вносить изменения, но это не надежное решение. Можете ли вы предложить какой-либо другой альтернативный способ, который является каноническим? так что это также может улучшить производительность.
Никунь Сатасия
1
@NikunjSatasiya - Извините, что вернулся так поздно. Нет способа сделать это без переписывания архива. Подумай о том, что должно произойти. В файле архива есть каталог с именами файлов и индексом для сжатого содержимого. Это не запись с фиксированной или фиксированной длиной, где вы можете изменить длину. Возможно, вы могли бы с бинарным редактором - но тогда указатели на файлы и их сжатые данные из «каталога» будут испорчены. Может быть, вы могли бы изменить имя файла и сохранить ту же длину. Серьезный клудж, скорее всего, нет.
Пост
1
А затем рассмотрите, является ли каталог файлов сжатым или зашифрованным. Никакие изменения извне не будут возможны. Я предполагаю, что если формат файла .7z был спроектирован с самого начала для обработки переименований на месте, и это было сделано разработчиком в проекте, это могло бы быть возможно, но мы далеки от этого. Я чувствую твою боль!
FastAl