3

I have to create a zip file from set of urls. and it should have a proper folder structure. So i tried like

   public async Task<byte[]> CreateZip(Guid ownerId)
    {
        try
        {
            string startPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "zipFolder");//base folder
            if (Directory.Exists(startPath))
            {
                DeleteAllFiles(startPath);
                Directory.Delete(startPath);
            }
            Directory.CreateDirectory(startPath);

            string zipPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{ownerId.ToString()}"); //folder based on ownerid
            if (Directory.Exists(zipPath))
            {
                DeleteAllFiles(zipPath);
                Directory.Delete(zipPath);
            }

            Directory.CreateDirectory(zipPath);
            var attachemnts = await ReadByOwnerId(ownerId);

            attachemnts.Data.ForEach(i =>
            {
                var fileLocalPath = $"{startPath}\\{i.Category}";
                if (!Directory.Exists(fileLocalPath))
                {
                    Directory.CreateDirectory(fileLocalPath);
                }
                using (var client = new WebClient())
                {
                    client.DownloadFile(i.Url, $"{fileLocalPath}//{i.Flags ?? ""}_{i.FileName}");
                }
            });
            var zipFilename = $"{zipPath}//result.zip";

            if (File.Exists(zipFilename))
            {
                File.Delete(zipFilename);
            }

            ZipFile.CreateFromDirectory(startPath, zipFilename, CompressionLevel.Fastest, true);


            var result = System.IO.File.ReadAllBytes(zipFilename);
            return result;
        }
        catch (Exception ex)
        {
            var a = ex;
            return null;
        }
    }

currently im writing all files in my base directory(may be not a good idea).corrently i have to manually delete all folders and files to avoid exception/unwanted files. Can everything be written in memory?

What changes required to write all files and folder structure in memory?

hilda_sonica_vish
  • 727
  • 3
  • 10
  • 31
  • Is it the source files or the final ZIP file that you want in memory? To create the ZIP file you can use a `MemoryStream`; reference [here](https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream?view=netframework-4.8) – Peter Smith Dec 30 '19 at 08:42
  • i want to create a source file/folder structure from urls, i want tht also in memory. you can see my foreach for creating folder. – hilda_sonica_vish Dec 30 '19 at 08:54
  • I know of no way to create the folder structure in memory. Depending on your deployment environment can you create a temporary working folder on your server that is not in your application folder. We use such a thing frequently. – Peter Smith Dec 30 '19 at 08:56
  • As @PeterSmith said I would create a temp work folder. Eg a new Guid, so something like: "/xxxx-xxxx-xxxx-xxxx/Folder-To-Zip/...." – Kiksen Dec 30 '19 at 09:03
  • you can use the answer from [this question](https://stackoverflow.com/questions/29647570/how-to-create-ziparchive-from-files-in-memory-in-c). But you have to call `zipArchive.CreateEntry` with a dir name in front of file name, like `zipArchive.CreateEntry($"{startPath}\\{attachment.FileName}"` – oleksa Dec 30 '19 at 09:10
  • how to maintain the folder structure inside zip then? – hilda_sonica_vish Dec 30 '19 at 09:14
  • what do you mean by "maintain" sorry? You can create zip entries (write files into zip archive) by using the `CreateEntry` method. However you can put folder names of entry is being created (path) like `CreateEntry("folderInZip\\subfolderInZip\\file.txt")`. This will create zip archive entry `file.txt` that is located in the `folderInZip\subfolderInZip` path. – oleksa Dec 30 '19 at 09:51

2 Answers2

1

No you can't. Not with the built in Dotnet any way.

enter image description here

As per my comment I would recommend storing the files in a custom location based on a Guid or similar. Eg:

"/xxxx-xxxx-xxxx-xxxx/Folder-To-Zip/....".

This would ensure you could handle multiple requests with the same files or similar file / folder names.

Then you just have to cleanup and delete the folder again afterwards so you don't run out of space.

Kiksen
  • 1,559
  • 1
  • 18
  • 41
0

Hope the below code does the job.

public async Task<byte[]> CreateZip(Guid ownerId)
        {
            try
            {
                string startPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}_zipFolder");//folder to add

                Directory.CreateDirectory(startPath);

                var attachemnts = await ReadByOwnerId(ownerId);
                attachemnts.Data = filterDuplicateAttachments(attachemnts.Data);
                //filtering youtube urls
                attachemnts.Data = attachemnts.Data.Where(i => !i.Flags.Equals("YoutubeUrl", StringComparison.OrdinalIgnoreCase)).ToList();

                attachemnts.Data.ForEach(i =>
                {
                    var fileLocalPath = $"{startPath}\\{i.Category}";
                    if (!Directory.Exists(fileLocalPath))
                    {
                        Directory.CreateDirectory(fileLocalPath);
                    }
                    using (var client = new WebClient())
                    {
                        client.DownloadFile(i.Url, $"{fileLocalPath}//{i.Flags ?? ""}_{i.FileName}");
                    }
                });

                using (var ms = new MemoryStream())
                {
                    using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
                    {
                        System.IO.DirectoryInfo di = new DirectoryInfo(startPath);
                        var allFiles = di.GetFiles("",SearchOption.AllDirectories);
                        foreach (var attachment in allFiles)
                        {
                            var file = File.OpenRead(attachment.FullName);

                            var type = attachemnts.Data.Where(i => $"{ i.Flags ?? ""}_{ i.FileName}".Equals(attachment.Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                            var entry = zipArchive.CreateEntry($"{type.Category}/{attachment.Name}", CompressionLevel.Fastest);
                            using (var entryStream = entry.Open())
                            {
                                file.CopyTo(entryStream);
                            }
                        }
                    }
                    var result = ms.ToArray();
                    return result;
                }
            }
            catch (Exception ex)
            {
                var a = ex;
                return null;
            }
        }
hilda_sonica_vish
  • 727
  • 3
  • 10
  • 31