---
name: ironzip
description: >
  Create, read, edit and extract archives in C#/.NET using IronZIP (the `IronZip` NuGet
  package). Use when the task involves ZIP/TAR/GZIP/BZIP2 archives, compressing or
  decompressing files, password-protected or AES-encrypted ZIPs, adding/deleting/replacing
  archive entries, listing archive contents, zipping a folder (e.g. a folder of PDFs or
  images), building an archive from a Stream/byte[], compression levels, or whenever a
  project already references `IronZip`, `IronZipArchive`, `IronTarArchive`,
  `IronGZipArchive`, or `IronBZip2Archive`.
---

# IronZIP (C# / .NET)

IronZIP is a small, **pure-managed** .NET library for creating, reading, editing and
extracting ZIP, TAR, GZIP and BZIP2 archives, with Traditional/AES-128/AES-256 password
protection for ZIP. There is no native engine to install or configure — one NuGet package
covers every supported runtime and OS.

## Scope of this skill

| | |
|---|---|
| Package | `IronZip` (one package, no platform variants) |
| Versions | 2024.x – 2026.x (verified against 2026.8.2) |
| Namespaces | `IronZip`, `IronZip.Enum` |
| Runtimes | .NET Framework 4.6.2+, .NET Standard 2.0+, .NET Core 3.1+, .NET 5–10 (single `netstandard2.0` assembly) |
| Formats | ZIP (`IronZipArchive`), TAR (`IronTarArchive`), GZIP (`IronGZipArchive`), BZIP2 (`IronBZip2Archive`) |

No async API exists on any of these types — every call is synchronous. Wrap in `Task.Run`
if a server codepath needs to avoid blocking.

## Install

```bash
dotnet add package IronZip
```

That's the whole install — `IronZip` is pure managed (its only runtime dependencies,
`IronSoftware.Common`, `ICSharpCode.SharpZipLib`, `Newtonsoft.Json`, resolve automatically
via NuGet). There is no Linux/macOS/ARM variant to choose and nothing to download at first
run. (NuGet's canonical package id is `IronZIP`; `dotnet add package IronZip` resolves to
it too since NuGet ids are case-insensitive — the C# namespace and assembly are `IronZip`
either way.)

## Licensing — do this first, every time

```csharp
IronZip.License.LicenseKey = Environment.GetEnvironmentVariable("IRONZIP_LICENSE_KEY");
if (!IronZip.License.IsLicensed)
    Console.Error.WriteLine("IronZIP is unlicensed — operations will fail once the trial grace period ends.");
```

Rules:

- Read the key from the environment (`IRONZIP_LICENSE_KEY`) or user secrets. **Never**
  inline a key in source, never write one into a file you commit, never echo one to the
  terminal. (.NET Framework apps may instead set `<add key="IronZip.LicenseKey"
  value="..."/>` in `Web.config`/`App.config`'s `appSettings`; .NET Core apps may use an
  `"IronZip.LicenseKey"` entry in `appsettings.json`.)
- **Treat a missing key as a blocker, not a warning.** Confirmed by running the library
  unlicensed: operations (seen on `SaveAs`, and on `FromDirectory` — assume any real
  operation, not just saving) throw `IronSoftware.Exceptions.LicensingException:
  Production License Required`, with the message noting development use is free for 7 days
  and production use requires a license. Unlike IronPDF/IronOCR there is no watermark
  fallback — an archive has nothing to watermark, so the library simply refuses once the
  grace period lapses. If `IsLicensed` is false, say so and ask for a key rather than
  building on top of calls that will throw. Trial keys:
  <https://ironsoftware.com/csharp/zip/licensing/>.
- `IronZip.License.IsValidLicense(key)` checks a key without applying it.
- `IronZip.License.DisableAppAnalytics()` opts out of the library's anonymous analytics.

## Running a one-off archive task from the terminal

Requires only the .NET SDK. On **.NET 10+**, a single file is the whole program:

```bash
cat > /tmp/task.cs <<'EOF'
#:package IronZip@2026.8.2
using IronZip;
IronZip.License.LicenseKey = Environment.GetEnvironmentVariable("IRONZIP_LICENSE_KEY");
using var archive = new IronZipArchive();
archive.Add("report.pdf");
archive.SaveAs("report.zip");
EOF
dotnet run /tmp/task.cs
```

Unlike IronPDF/IronOCR, IronZIP does **not** need `#:property PublishAot=false` — it is
pure managed with no Chromium/Tesseract-style runtime code generation, and a plain
`dotnet run` of the file above works without it (verified).

On older SDKs, use a scratch project:

```bash
dotnet new console -o /tmp/ironzip-scratch && cd /tmp/ironzip-scratch
dotnet add package IronZip
# write Program.cs, then:
dotnet run
```

## Recipes

Every call below is verified against the shipped assembly (constructor overloads, default
parameter values, and return types were confirmed via reflection over
`IronZip.dll`, not just the docs site — see the Rules section for two places the public
docs site itself disagreed with the real API).

### Create an archive

```csharp
using IronZip;

using (var archive = new IronZipArchive())          // Compression defaults to 9
{
    archive.Add("./assets/image1.jpg");             // Add == AddArchiveEntry, same thing
    archive.Add("./assets/image2.jpg");
    archive.SaveAs("output.zip");                    // no more Add() after this
}

using var tar   = new IronTarArchive();    tar.Add("file.txt");    tar.SaveAs("output.tar");
using var bzip2 = new IronBZip2Archive();  bzip2.Add("file.txt");  bzip2.SaveAs("output.bz2");
using var gzip  = new IronGZipArchive();   gzip.Add("output.tar"); gzip.SaveAs("output.tgz"); // gzip-wrap a tar
```

`new IronZipArchive(9)` / `new IronGZipArchive(9)` set the compression level explicitly —
`0` is weakest, `9` is default and highest. `IronTarArchive`/`IronBZip2Archive` have no
compression parameter (TAR is uncompressed; BZIP2 has its own fixed scheme).

Build straight from a whole file set instead of an empty archive:

```csharp
using var a1 = IronZipArchive.FromFile("report.pdf");            // new archive seeded with ONE file
using var a2 = IronZipArchive.FromFiles(new[] { "a.pdf", "b.pdf" });
using var a3 = IronZipArchive.FromDirectory("./reports");         // seeds every file found under the directory
a3.SaveAs("reports.zip");
```

**`FromFile`/`FromFiles`/`FromDirectory` build a brand-new archive from that path — they do
not open an existing archive for editing.** (This corrects the public examples page, which
shows `IronZipArchive.FromFile("existing.zip")` used to *open* an existing ZIP; per the
shipped XML docs its actual contract is "creates an archive with a specific file to add to
it," i.e. it produces a new archive containing that one path as an entry. To open an
existing archive, use the constructor or `FromArchive` below.)

### Open, list, and edit an existing ZIP

```csharp
using (var archive = new IronZipArchive("existing.zip"))   // or IronZipArchive.FromArchive("existing.zip")
{
    Console.WriteLine(archive.Count);                       // entry count
    foreach (IronZip.Entry entry in archive.Entries())       // List<Entry>
        Console.WriteLine($"{entry.Name} {entry.Size} bytes, comment={entry.Comment}");

    if (archive.Contains("old.txt"))
        archive.Delete("old.txt");
    archive.ReplaceEntry("draft.txt", "final.txt");
    archive.Add("new-file.txt");
    archive.Comment = "Rebuilt archive";                     // whole-archive comment
    archive.SaveAs("result.zip");
}
```

`Entry` (verified properties): `Name`, `Size`, `CompressedSize`, `Comment`, `IsDirectory`,
`IsFile`, `IsCrypted`, `DateTime`, `Crc`, `Version`. TAR only exposes names —
`IronTarArchive.GetArchiveEntryNames()` returns `List<string>`, not a richer `Entry` list.

### Password protection (ZIP only)

```csharp
using IronZip;
using IronZip.Enum;   // EncryptionMethods: Traditional, AES128, AES256

using (var archive = new IronZipArchive(9))
{
    archive.Encrypt("P@ssw0rd", EncryptionMethods.AES256);   // SetPassword is a synonym
    archive.Add("./assets/image1.jpg");
    archive.SaveAs("secure.zip");
}

// Open a protected archive: password is the second constructor argument
using (var archive = new IronZipArchive("secure.zip", "P@ssw0rd"))
{
    archive.RemoveEncryption();       // strip the password
    archive.SaveAs("plain.zip");
}

IronZipArchive.ExtractArchiveToDirectory("secure.zip", "extracted", "P@ssw0rd");
```

Or bundle encryption into the save call via `ZipSaveOptions` instead of calling
`Encrypt`/`Compression` separately:

```csharp
archive.SaveAs("secure.zip", new ZipSaveOptions {
    EncryptionMethod = EncryptionMethods.AES256, Password = "P@ssw0rd", Compression = 9
});
```

### Extract archives

```csharp
IronZipArchive.ExtractArchiveToDirectory("output.zip", "extracted");             // password optional 3rd arg
IronTarArchive.ExtractArchiveToDirectory("output.tar", "extracted");
IronBZip2Archive.ExtractArchiveToDirectory("output.bz2", "extracted");
IronGZipArchive.ExtractArchiveToDirectory("output.gz", "extracted");
IronGZipArchive.ExtractTGZArchiveToDirectory("output.tgz", "extracted");         // gzip-wrapped tar, one call
```

All four `ExtractArchiveToDirectory` overloads are **static** — call them on the type, not
an instance. There is no extract-to-`Stream`/`byte[]` method in the shipped API; extract to
a directory (a temp one if the bytes are needed in memory afterwards).

### Build from a Stream or byte[] (ZIP only)

```csharp
using var archiveFromStream = new IronZipArchive(memoryStream, password: null);
using var archiveFromBytes  = new IronZipArchive(zipBytes, password: null);
```

Only `IronZipArchive` has these two constructors — TAR/GZIP/BZIP2 only construct from a
file path or blank.

## Working with IronPDF / IronOCR

IronZIP composes with other Iron products by working on the files they produce:

- **Zip a folder of generated PDFs:** render with IronPDF (see the **ironpdf** skill), then
  `IronZipArchive.FromDirectory("./reports").SaveAs("reports.zip")`.
- **Archive scanned images before/after OCR:** IronOCR reads images out of a ZIP only if
  you extract first — `IronZipArchive.ExtractArchiveToDirectory("scans.zip", "scans")`,
  then load each file with IronOCR (see the **ironocr** skill).

## Deployment

IronZIP has no native binaries, no browser/Chromium process, and no temp-directory or
license-server configuration surface — deployment is exactly what you'd expect of a
pure-managed netstandard2.0 library.

| Environment | What to do |
|---|---|
| Docker / Linux / macOS / ARM | Nothing special — no native deps to install, no platform-specific package to pick. |
| Azure / AWS Lambda / IIS | Works on any tier; just ensure the process can write to wherever `SaveAs`/`ExtractArchiveToDirectory` point (Lambda: use `/tmp`). |
| Container image size | Small — no bundled native runtime, unlike IronPDF's Chromium or IronOCR's Tesseract data. |

## When something fails

| Symptom | Cause and fix |
|---|---|
| `IronSoftware.Exceptions.LicensingException: Production License Required` | No valid licence, or the 7-day dev grace period has ended. Set `IronZip.License.LicenseKey` before the first call — enforcement isn't limited to `SaveAs`, so set it before doing anything. |
| `FromFile("existing.zip")` produces a 1-entry archive, not the original contents | `FromFile`/`FromFiles`/`FromDirectory` always build a **new** archive; they never open one. Use `new IronZipArchive("existing.zip")` or `IronZipArchive.FromArchive(path, password)` to open. |
| `Add()` after `SaveAs()`/`Save()` has no effect or throws | "Users cannot add additional entries after saving" — construct a new archive (or reopen the saved one) instead of continuing to mutate a saved instance. |
| Can't open a protected ZIP | Wrong/missing password. Pass it as the constructor's second argument or via `ExtractArchiveToDirectory(path, dir, password)`. |
| Need the archive's bytes without touching disk | Not directly supported — there is no `Save`/`Extract` overload targeting `Stream`/`byte[]`; save/extract to a (temp) file and read it back. |
| TAR entries missing size/date/comment | `IronTarArchive.GetArchiveEntryNames()` only returns names (`List<string>`). Only `IronZipArchive.Entries()` returns rich `Entry` objects. |

## Rules

- **Never invent a member.** Confirm against the XML documentation shipped in the package
  before writing code:
  `grep -o 'name="[MPF]:IronZip\.[^"]*"' ~/.nuget/packages/ironzip/<version>/lib/netstandard2.0/IronZip.xml`
  That file — and the compiled `IronZip.dll` itself via reflection if the XML text is
  ambiguous about a return type or default parameter — is the authoritative surface for the
  installed version. The public examples site is not always consistent with it: the
  `FromFile`-to-open-an-existing-archive example described above is one confirmed instance;
  treat any docs-site snippet that claims to "open" via `FromFile`/`FromFiles`/`FromDirectory`
  with suspicion and re-check against the XML docs.
- Keep licence keys out of source and out of terminal output.
- Say when a call will fail unlicensed rather than presenting its (untested) output as final.
- `Add`/`AddArchiveEntry` are the same method under two names — either is fine.
- No async API on any archive type — don't invent `...Async` overloads.
- Official docs: <https://ironsoftware.com/csharp/zip/docs/>. Support:
  support@ironsoftware.com.
