skip to Main Content

I am able to move the directory in azure using ShareDirectoryClient successfully.

using System;
using System.Threading.Tasks;
using Azure.Storage.Files.Shares;

namespace SO69798149
{
    class Program
    {
        const string MyconnectionString = "DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key";
        const string MyshareName = "share-name";
        const string SourceDirectoryName = "source-directory-name";
        private const string RenamedDirectoryName = "new-directory-name";
        
        static async Task Main(string[] args)
        {
            ShareClient myshare = new ShareClient(MyconnectionString, MyshareName);
            ShareDirectoryClient sourceDirectoryClient = myshare.GetDirectoryClient(SourceDirectoryName);
            ShareDirectoryClient targetDirectoryClient = myshare.GetDirectoryClient(RenamedDirectoryName);
            await RenameDirectory(sourceDirectoryClient, targetDirectoryClient);
            Console.WriteLine("Directory renamed.");
        }

        static async Task RenameDirectory(ShareDirectoryClient sourceDirectoryClient,
            ShareDirectoryClient targetDirectoryClient)
        {
            //Create target directory
            await targetDirectoryClient.CreateIfNotExistsAsync();
            //List files and folders from the source directory
            var result = sourceDirectoryClient.GetFilesAndDirectoriesAsync();
            await foreach (var items in result.AsPages())
            {
                foreach (var item in items.Values)
                {
                    if (item.IsDirectory)
                    {
                        //If item is directory, then get the child items in that directory recursively.
                        await RenameDirectory(sourceDirectoryClient.GetSubdirectoryClient(item.Name),
                            targetDirectoryClient.GetSubdirectoryClient(item.Name));
                    }
                    else
                    {
                        //If item is file, then copy the file and then delete it.
                        var sourceFileClient = sourceDirectoryClient.GetFileClient(item.Name);
                        var targetFileClient = targetDirectoryClient.GetFileClient(item.Name);
                        await targetFileClient.StartCopyAsync(sourceFileClient.Uri);
                        await sourceFileClient.DeleteIfExistsAsync();
                    }
                }
            }
            //Delete source directory.
            await sourceDirectoryClient.DeleteIfExistsAsync();
        }
        
    }
}

I am moving the directory in azure using ShareDirectoryClient. Here How can we zip the folder after moving it.

My Approach:

using System.IO.Compression;
ZipFile.CreateFromDirectory(sourceDirectoryClient.Path, targetDirectoryClient.Path);

Error: Could not find a part of the path ‘/app/NewFolder/test.zip’.

Please assist me in resolving the issue

Note: We can also use the below library
https://github.com/icsharpcode/SharpZipLib

Zipping a directory using C# and SharpZipLib

void fastcompressDirectory(string DirectoryPath, string OutputFilePath, int CompressionLevel = 9)
{
    ICSharpCode.SharpZipLib.Zip.FastZip z = new ICSharpCode.SharpZipLib.Zip.FastZip();
    z.CreateEmptyDirectories = true;
    z.CreateZip(OutputFilePath, DirectoryPath, true, "");

    if (File.Exists(OutputFilePath))
        Console.WriteLine("D0ne");
    else
        Console.WriteLine("Failed");
}

The above code will zip all the folder contents to a new zip file. How can we achieve the same in azure sharedirectoryclient directory.

2

Answers


  1. My understanding is that you want to compress a directory from Azure File Share and store the result zip archive on the same Azure File Share.

    The problem you have with ZipFile.CreateFromDirectory is related to paths and where you execute the code. If you substitute those paths you will have something like:

    ZipFile.CreateFromDirectory("/app/NewFolder", "/app/NewFolder.zip");
    

    Those paths are treated as local to your application (if your app is in C:MyApp then they will resolve to C:MyAppappNewFolder). ZipFile does not use Azure File Share and this is the main problem.

    You can try to use Azure Data Factory to zip folders or maybe Josefs Ottosson tutorial will be helpful if you want to implement this in your code.

    Or maybe you can use this approach if you attach the share to the machine on which your app is running then you would operate on files on this machine.

    Login or Signup to reply.
  2. I’ve modified your code to include zip file creation and upload

    Here is your Main method. It now includes ZipArchive kept in memory. Archive is being passed into your recursive method so it can write listed files into the Zip stream.

    After running your method we need to Create new file on share and upload its contents

    static async Task Main(string[] args)
    {
        ShareClient myshare = new ShareClient(MyconnectionString, MyshareName);
        ShareDirectoryClient sourceDirectoryClient = myshare.GetDirectoryClient(SourceDirectoryName);
        ShareDirectoryClient targetDirectoryClient = myshare.GetDirectoryClient(RenamedDirectoryName);
    
        using (var memory = new MemoryStream())
        {
            using (var zip = new ZipArchive(memory, ZipArchiveMode.Create, true))
            {
                await RenameDirectory(sourceDirectoryClient, targetDirectoryClient, zip);
            }
            
            var zipfile = await myshare.GetRootDirectoryClient().CreateFileAsync(RenamedDirectoryName + ".zip", memory.Length);
            memory.Seek(0, SeekOrigin.Begin);
            await zipfile.Value.UploadAsync(memory);
        }
        Console.WriteLine("Directory renamed.");
    }
    
    

    Your RenameDirectory method needs to include another parameter path to keep track of recursive subdirectory traverse which is used to name files in zip archive including directory structure.

    static async Task RenameDirectory(ShareDirectoryClient sourceDirectoryClient,
        ShareDirectoryClient targetDirectoryClient, ZipArchive zip, string path = "")
    {
        //Create target directory    
        await targetDirectoryClient.CreateIfNotExistsAsync();
        //List files and folders from the source directory
        var result = sourceDirectoryClient.GetFilesAndDirectoriesAsync();
        
        await foreach (var items in result.AsPages())
        {
            foreach (var item in items.Values)
            {
                if (item.IsDirectory)
                {
                    //If item is directory, then get the child items in that directory recursively.
                    await RenameDirectory(sourceDirectoryClient.GetSubdirectoryClient(item.Name),
                        targetDirectoryClient.GetSubdirectoryClient(item.Name), zip, $"{path}{item.Name}/");
                }
                else
                {
                    //If item is file, then copy the file and then delete it.
                    var sourceFileClient = sourceDirectoryClient.GetFileClient(item.Name);
                    var targetFileClient = targetDirectoryClient.GetFileClient(item.Name);
                    await targetFileClient.StartCopyAsync(sourceFileClient.Uri);
                    
                    var file = await sourceFileClient.DownloadAsync();
                    var zipEntry = zip.CreateEntry(path + item.Name);
                    using (var zipEntryStream = zipEntry.Open())
                    {
                        await file.Value.Content.CopyToAsync(zipEntryStream);
                    }
                    
                    await sourceFileClient.DeleteIfExistsAsync();
                }
            }
        }
        
        //Delete source directory.
        await sourceDirectoryClient.DeleteIfExistsAsync();
    }
    

    I kept all your code without modification – so old behaviour is stille there (new folder will still get created and old one will be deleted). Additional outcome is that app should create a zip file in root of your share. I think it should be easy to remove all the ‘target’ folder and files creation from your code (if you don’t need it anymore). I hope it will be easy to identify changes.

    Obviously I wasn’t trying to encapsulate all that zip building into separate IDisposable class to make it clear what should happen where.

    Keep that in mind – zip file is being created in memory of your application. If you will have a lot of files then memory consumption of your app might grow really fast – so watch out! 😉

    Another suggestion would be that you should not delete any files from share until you save complete zip. Otherwise in case of exception you will lose files which has been ‘moved’ to in-memory zip. That might mean that you will have to trafverse source folder twice but it much more safe.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search