C# - VisualStudioもライブラリも使わずにZipファイルを生成する

# 環境
Windows10 (7も多分いけるはず)

# コンパイル

事前にcscにパスを通しておく。
`C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe`

```compile.bat

csc /r:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.IO.Compression.FileSystem.dll ^
    /r:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.IO.Compression.dll %*
```

下記でコンパイルできる。
`compile.bat ソース名.cs`

# ソースコード

```csharp

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.IO.Compression; // to use zip

class ZipTest : Form
{
    ZipTest()
    {
        var btn = new Button(){
            Size = new Size(200,25),
            Text = "Save zip file",
        };
        btn.Click += (s,e)=>{
            string destPath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "ZipTest_Output.zip");
            CreateZipFile(destPath);
        };
        Controls.Add(btn);

    }

    void CreateZipFile(string destZipPath)
    {
        try {
            //  ZipFile.Open で Zipを作成するとき、すでにファイルが存在していると例外が発生する。
            //  上書きしたい場合は、すでにファイルが存在する場合は削除しておく。
            // if (File.Exists(destZipPath)) {
            //     File.Delete(destZipPath);
            // }

            using( ZipArchive archive = ZipFile.Open(destZipPath, ZipArchiveMode.Create) ) {
                ZipArchiveEntry entry;

                entry = archive.CreateEntry("Test1.txt", CompressionLevel.Optimal);
                using (StreamWriter writer = new StreamWriter(entry.Open()))
                {
                    writer.WriteLine("FileContentSample-1");
                }

                entry = archive.CreateEntry(@"hoge\Test2.txt", CompressionLevel.Optimal);
                using (StreamWriter writer = new StreamWriter(entry.Open()))
                {
                    writer.WriteLine("FileContentSample-2");
                }
                
                // 既存のファイル（第一引数）を読み込んでzip内にファイルをつくる場合
                // archive.CreateEntryFromFile( @"C:\Test.txt", "a.txt", CompressionLevel.Optimal );
            }
        }
        catch(IOException e) {
            MessageBox.Show(e.ToString());
        }        
        catch(UnauthorizedAccessException e) {
            MessageBox.Show(e.ToString());
        }
    }
    
    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new ZipTest());
    }
}

```

フォルダからzipを作成する場合は

https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.zipfile.createfromdirectory?view=net-7.0

※zipにフォルダを追加するには、archive.CreateEntryFromFile で頑張るしかなさそう。

# もう少し実用的なサンプル

指定された １個のフォルダ または 複数のファイル（フォルダを含んではいけない）をzip化する。 

```cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.IO.Compression; // to use zip


class ZipMaker : Form
{

    static bool PreCheck(string[] args, out bool dirMode, out string errMsg)
    {
        errMsg = null;

        if (args.Length==1 && Directory.Exists(args[0]))
        {
            dirMode = true;
            return true;
        }
        else
        {
            dirMode = false;
            foreach (string arg in args)
            {
                if (!File.Exists(arg))
                {
                    if (Directory.Exists(arg))
                    {
                        errMsg = "This tool does not support multiple entries including folder. Only supports 1 folder, or files";
                    }
                    else
                    {
                        errMsg = "File not found: \"" + arg + "\"";
                    }
                    return false;
                }
            }
        }
        return true;
    }

    static void CreateZipFromFiles(string destZipPath, string[] files)
    {
        // https://stackoverflow.com/questions/15133626/creating-directories-in-a-ziparchive-c-sharp-net-4-5
        // https://docs.microsoft.com/ja-jp/dotnet/api/system.io.compression.ziparchive?view=netcore-3.1

        try
        {
            if (File.Exists(destZipPath))
            {
                // すでにファイルが存在する場合は削除する。
                File.Delete(destZipPath);
            }
            using( ZipArchive archive = ZipFile.Open(destZipPath, ZipArchiveMode.Create) )
            {
                foreach(string s in files)
                {
                    string path = Path.GetFullPath(s);
                    if (File.Exists(path))
                    {
                        archive.CreateEntryFromFile( path, Path.GetFileName(path), CompressionLevel.Optimal );
                    }
                    else
                    {
                        if (Directory.Exists(path))
                        {
                            Console.WriteLine("This tool does not support multiple entries including folder. Only supports 1 folder, or files");
                            Console.WriteLine("Ignored:\"" + path + "\"");
                        }
                        else
                        {
                            Console.WriteLine("File not found.");
                            Console.WriteLine("Ignored:\"" + path + "\"");
                        }
                    }
                }
            }
        }
        catch(IOException e)
        {
            MessageBox.Show(e.ToString());
        }        
        catch(UnauthorizedAccessException e)
        {
            MessageBox.Show(e.ToString());
        }
    }


    static string DestPathFromFileSaveAs(string defaultZipPath, string defaultZipName)
    {
        SaveFileDialog dlg = new SaveFileDialog();

        dlg.FileName = defaultZipName;
        dlg.InitialDirectory = defaultZipPath;
        dlg.Filter = "ZIP file(*.zip)|*.zip";
        dlg.FilterIndex = 1;
        dlg.Title = "Select file name to save";
        dlg.RestoreDirectory = true;
        dlg.OverwritePrompt = true;
        //dlg.CheckPathExists = true;

        if ( dlg.ShowDialog() == DialogResult.OK )
        {
            return dlg.FileName;
        }
        return null;
    }


    [STAThread]
    static void Main(string[] args)
    {
        bool dirMode;
        string errMsg;

        if (args.Length==0){return;}
        string path0 = Path.GetFullPath(args[0]);
        string parent0 = Path.GetDirectoryName(path0);
        
        if ( !PreCheck(args, out dirMode, out errMsg))
        {
            MessageBox.Show(errMsg);
        }

        string destPath;
        if (dirMode)
        {
            destPath = DestPathFromFileSaveAs(parent0, Path.GetFileName(path0) + ".zip");
            if(destPath!=null)
            {
                ZipFile.CreateFromDirectory(path0, destPath);// src folder, dest zip
            }
        }
        else
        {
            if (args.Length >= 2)
            {
                destPath = DestPathFromFileSaveAs(parent0, Path.GetFileName(parent0) + ".zip");
            }
            else
            {
                destPath = DestPathFromFileSaveAs(parent0, Path.GetFileName(path0) + ".zip");
            }

            if(destPath!=null)
            {
                CreateZipFromFiles(destPath, args);
            }
        }
    }
}

```

# 参考サイト
- https://docs.microsoft.com/ja-jp/dotnet/api/system.io.compression.ziparchive?view=netcore-3.1
- https://stackoverflow.com/questions/15133626/creating-directories-in-a-ziparchive-c-sharp-net-4-5