The SevenZip library for .NET provides classes to create, modify and extract different kinds of archives by using the native 7z library from Igor Pavlov. Additionally, it contains the original SDK code which allows compressing and decompressing binary data using the LZMA method.
The library is written in C# and supports .NET 4.8 and .NET6 on Windows, and .NET 8 on Windows and Linux.
MIT
The following binaries embedded in the NuGet package are licensed under the GNU LGPL, GNU LGPL with 'unRAR license restrictions' and BSD 3-clause license:
- 7z.dll
- 7z.so
The files located in src/SevenZip/CoreSdk
where published under public domain.
All other files are licensed with the MIT license.
- Original SDK code for LZMA compression.
- The UUIDs for the COM interfaces were taken from the 7-Zip C/C++ library.
- The format detection is inspired by the original SevenZipSharp library,
which has been archived, but has some forks which are still being maintained.
- Most signatures can be obtained from Wikipedia - List of file signatures.
- Multi-part archives are not supported. If there is a requirement, this may be added in a future release.
- Creation of executable archives is not supported.
- Encryption is not yet fully supported. It can however be set by adding the parameters
"he" and/or "em" (for Zip archives only) to the
CompressProperties
class.
The .NET 8 builds of SevenZip
can run under Linux. The native 7z Linux
library was build from the original repository at https://github.com/mcmilk/7-Zip
by using the following commands:
git clone https://github.com/mcmilk/7-Zip.git
cd 7-zip/CPP/7zip/Bundles/Format7zF
make -f makefile.gcc
The different bundles and the formats they support are explained here: https://github.com/mcmilk/7-Zip/blob/master/DOC/readme.txt.
Clone the project into any location and add a reference to it.
<ItemGroup>
<ProjectReference Include="..\..\src\SevenZip\SevenZip.csproj" />
</ItemGroup>
The native 7z library is part of this repository, but not linked directly by the SevenZip
project. This can be done by importing the Native7zReferences.target
file in a .csproj
, or with
the following snippet:
<ItemGroup>
<None Include="..\..\runtimes\win\native\7z.dll" Link="7z.dll" CopyToOutputDirectory="PreserveNewest" />
<None Include="..\..\runtimes\linux\native\7z.so" Link="7z.so" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
The path to the native library can however be specified by setting the ArchiveConfig.NativeLibraryPath
property, which is then passed to an ArchiveReader
or ArchiveWriter
.
Not available yet
<ItemGroup>
<PackageReference Include="Exocad.SevenZip" Version="1.0.0" />
</ItemGroup>
The NuGet package includes the native libraries, a separate reference is not required.
The ArchiveReader
can extract specific files only or an entire archive. It operates
with System.IO.Stream
, which allows extracting to memory, files or anything else that
can be represented as stream.
A stream to use for extraction is obtained by invoking a callback passed
to the Extract
method, which has to return the stream to use for a given entry.
The easiest way to extract an entire archive is to use the ExtractAll
method:
using SevenZip
using var reader = new ArchiveReader("archive.7z");
reader.ExtractAll(targetDir, ArchiveFlags.ApplyArchiveEntryTimestampsToFileStreams);
To extract a single entry (or specific entries), the Extract
methods can be used
with the indices of the entries to extract. The index of an entry can be found by
iterating over the ArchiveReader.Entries
property.
The following snippet shows how to extract a set of entries:
using SevenZip
bool CanExtract(ArchiveEntry entry)
{
return ...
}
using var reader = new ArchiveReader("archive.7z");
var indices = reader.Entries
.Where(entry => CanExtract(entry))
.Select(entry => entry.Index)
.TolArray();
reader.Extract(
indices,
entry => File.Open(Path.Join(baseDir, entry.Path), FileMode.Create, FileAccess.Write),
ArchiveFlags.ApplyArchiveEntryTimestampsToFileStreams |
ArchiveFlags.CloseArchiveEntryStreamAfterExtraction);
The ArchiveWriter
class can be used to create or update an archive. If the class is initialized
with a contructor expecting an ArchiveFormat
parameter, a new archive is created - even if an
archive already exists at the given location!
To update an existing archive, choose a constructor not expecting the ArchiveFormat
. The ArchiveWriter
will then detect the format from the existing archive (or throws an exception if it can't).
When adding new files to an archive an archive-path must be specified indicating the full path the new entry should have within the archive.
using SevenZip;
using SevenZip.Extensions;
// Create a new archive (or override an existing one)
using var writer = new ArchiveWriter(ArchiveFormat.SevenZip, "archive.7z");
// Add "./directory/filename.txt" as "archive/filename.txt" to the archive.
writer.AddFile("archive/filename.txt", "./directory/filename.txt");
// Add all files from "otherdir" to the archive, using a specific naming strategy.
writer.AddDirectory("./otherdir", NamingStrategy.RelativeToTopDirectoryInclusive);
// Write the changes
writer.Compress();
To modify or remove existing entries, use the ArchiveWriter.ExistingEntries
property to
search for the index of the entry to update or delete. ArchiveWriter.ReplaceEntry
and ArchiveWriter.DeleteEntry
can then be used to prepare the changes.
To actually write the changes, call ArchiveWriter.Compress
.
using SevenZip;
using SevenZip.Extensions;
// Create a new archive (or override an existing one)
using var writer = new ArchiveWriter("archive.7z");
// Remove entry with index 10.
writer.RemoveEntry(10);
// Replace entry 11 with the contents of another file.
writer.ReplaceEntry(11, "./contents/anotherfile.txt");
// Write the changes
writer.Compress();
Important |
---|
If an existing archive is modified, a local copy of the original data is stored in a temporary file which will be deleted again afterwards when calling Compress . This is required since simultaneous read and write operations are not supported. |
Once Compress
has been called, the ExistingEntries
properties is being updated. In most scenarios,
the method should only be called once and the ArchiveWriter
should then be disposed again. However,
for streams supporting both read and write operations, it may be called multiple times.