How to Rename Files and Folder in .rar .7z, .tar, .zip using C#
Asked Answered
F

2

12

I have a compressed file .rar .7z, .tar and .zip and I want to rename physical file name available in above compressed archived using C#.

I have tried this using a sharpcompress library but I can't find such a feature for rename file or folder name within .rar .7z, .tar and .zip file.

I also have tried using the DotNetZip library but its only support.Zip see what I have tried using DotNetZip library.

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());
            }

        }

But actually the same as above I also want for .7z, .rar and .tar, I tried many libraries but still I didn't get any accurate solution.

Please help me.

Fantoccini answered 23/12, 2019 at 6:4 Comment(6)
There is a var result = Path.ChangeExtension(myffile, ".jpg"); -> learn.microsoft.com/en-us/dotnet/api/…Evincive
Hi panoskarajohn, I want to do this on file within the archive listed on the question, is there any solution can u suggest?Fantoccini
I am sorry i do not have a clean solution for this, I am sure you can do the rename after the Extract() as zip.Evincive
Just to be sure, your endresult needs to be you want to rename the files inside the zipped archive?Evincive
Yes, I want to rename the files inside the zipped archive without extract the archive and archive formate can be anything .rar .7z, .tar or .zip.Fantoccini
In most formats, if not all, file and directory names are encoded with a variable size in the resulting binary file, so you can't just "patch" it, you have to reconstruct some parts of the file. Standard libraries don't do that. You'll have to get into each archive format and see how you can do it. Difficult task. Example: #32830339Brine
G
3

This is a simple console application to rename files in .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();
        }
    }
}
Gassman answered 30/12, 2019 at 20:50 Comment(3)
Thanks, Binara, for your response but as I can see in your valuable answer you are right we can rename a file in the zip archive as you showed in your answer, but if my file is large then? it will open the original file, copy entire content from that and write agin same content in another file and save the new file, I think it will be a time-consuming process. Have you any other solution please?Fantoccini
Try Parallel.ForEach instead of Sequential loop. I have changed the code accordingly.Gassman
Thanks Binara, I will try this solution for rename the file within .zip archive, but still, there is one issue like when I will modify any file within archive then it will re-compressing my whole zip so is there any solution for that?Fantoccini
R
2

Consider 7zipsharp:

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

7zip itself supports lots of archive formats (I believe all you mentioned) and 7zipsharp uses the real 7zip. I've used 7zipsharp for .7z files only but I bet it works for others.

Here's a sample of a test that appears to rename a file using ModifyArchive method, I suggest you go to school in it:

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

Here's the code simplified a bit. Note that the test compresses a 7z file for its test; that's immaterial it could be .txt, etc. Also note it finds the file by index in the dictionary passed to ModifyArchive. Consult documentation for how to get that index from a filename (maybe you have to loop and compare).

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")));
Recital answered 27/12, 2019 at 21:35 Comment(4)
Hi FastAI, Thanks for your response but I also have tried this library before but generally when we modify any file inside the archive either it's content or name, the archive is re-compressing so its taking time for re-compressing if the archive is large. As you are given sample code in your answer then I think you have extracted archive first using 'ExtractArchive' and then you do further modification but this is not a reliable solution, Can you please suggest any other alternative way witch is canonical? so it also can improve the performance.also.Fantoccini
@NikunjSatasiya - Sorry to come back so late. There's no way to do this without re-writing the archive. Think about what must happen. There is a directory in the archive file with the filenames, and an index to the compressed content. This is not a 'padded' / fixed length entry where you can change the length. Perhaps you could with a binary editor - but then indicies of files and their compressed data from the 'directory' would be screwed. Maybe you could change the filename like that and keep same length. Serious kludge, not a feature likely.Recital
And then consider if the directory of files is compressed or encrypted. No changes from the outside would be possible. I suppose if the .7z file format were designed from the beginning to handle in-place renames, and this were done by a dev on the project, this might be possible, but we are a long way down stream from that. I feel your pain!Recital
That's basically what he's asking, @FastAl. zip permits this (see zipnote or explorer in windows). 7z too (see 7za rn). If, for example, tar cannot, then that should be an addendum in the answer, not promoting a library which doesn't do the job that can be done.Malign

© 2022 - 2024 — McMap. All rights reserved.