.NET C#/VB
-
Read & Write Compressed Files
// AZUL CODING ---------------------------------------
// .NET C#/VB - Read & Write Compressed Files
// https://youtu.be/vbSbi196s58
using SharpCompress.Archives;
using SharpCompress.Common;
namespace AzulArchives;
class Program
{
static void Main(string[] args)
{
// Install the SharpCompress package first:
// dotnet add package SharpCompress
bool running = true;
while (running)
{
Console.WriteLine("\n Archive manager");
Console.WriteLine(new string('─', 70));
Console.WriteLine(" 1. Create archive from folder");
Console.WriteLine(" 2. Extract archive");
Console.WriteLine(" 3. Display archive contents");
Console.WriteLine(" 4. Read file from archive");
Console.WriteLine(" 5. Add file to archive");
Console.WriteLine(" 6. Remove file from archive");
Console.WriteLine(" 7. Exit");
Console.WriteLine(new string('─', 70));
string choice = GetInput(" Enter your choice >> ");
try
{
switch (choice)
{
case "1":
CreateArchiveFromFolder(GetInput(" Enter folder path >> "));
break;
case "2":
ExtractArchive(GetInput(" Enter archive path >> "));
break;
case "3":
DisplayArchiveContents(GetInput(" Enter archive path >> "));
break;
case "4":
ReadFileFromArchive(
GetInput(" Enter archive path >> "),
GetInput(" Enter filename to read >> ")
);
break;
case "5":
WriteFileToArchive(
GetInput(" Enter archive path >> "),
GetInput(" Enter filename to add >> ")
);
break;
case "6":
DeleteFileFromArchive(
GetInput(" Enter archive path >> "),
GetInput(" Enter filename to remove >> ")
);
break;
case "7":
running = false;
break;
default:
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(" Invalid choice. Please try again.");
Console.ResetColor();
continue;
}
if (running)
{
Console.WriteLine("\n Press any key to continue...");
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"\n Error: {ex.Message}");
Console.ResetColor();
Console.WriteLine("\n Press any key to continue...");
Console.ReadKey();
}
}
}
#region Extract and compress
static void CreateArchiveFromFolder(string folderPath)
{
if (!Directory.Exists(folderPath))
throw new DirectoryNotFoundException("Folder does not exist.");
string dest = $"{folderPath}.zip";
using var archive = ArchiveFactory.Create(ArchiveType.Zip);
archive.AddAllFromDirectory(folderPath);
archive.SaveTo(dest, CompressionType.Deflate);
Console.WriteLine($"\n Archive created: {dest}");
}
static void ExtractArchive(string archivePath)
{
using var archive = ArchiveFactory.Open(archivePath);
string destDir = Path.Combine(
Path.GetDirectoryName(archivePath) ?? "",
Path.GetFileNameWithoutExtension(archivePath)
);
Directory.CreateDirectory(destDir);
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(destDir, new ExtractionOptions
{
ExtractFullPath = true,
Overwrite = true
});
}
Console.WriteLine($"\n Extracted to folder: {destDir}");
}
#endregion
#region Read contents
static void DisplayArchiveContents(string archivePath)
{
using var archive = ArchiveFactory.Open(archivePath);
List<IArchiveEntry> entries = [.. archive.Entries.Where(e => !e.IsDirectory)];
Console.WriteLine(
$"\n {Path.GetFileName(archivePath)} • {archive.Type} • Total files: {entries.Count}"
);
Console.WriteLine(new string('─', 70));
Console.WriteLine($"{" Filename",-35} {"Size",-12} {"Compressed",-12} Ratio");
Console.WriteLine(new string('─', 70));
long totalSize = 0;
long totalCompressed = 0;
var groupedEntries = entries
.Select(e => new
{
Entry = e,
Directory = Path.GetDirectoryName(e.Key)?.Replace("\\", "/") ?? "",
FileName = Path.GetFileName(e.Key)
})
.OrderBy(e => e.Directory)
.ThenBy(e => e.FileName)
.ToList();
string? currentDir = null;
foreach (var item in groupedEntries)
{
totalSize += item.Entry.Size;
totalCompressed += item.Entry.CompressedSize;
if (item.Directory != currentDir)
{
if (!string.IsNullOrEmpty(item.Directory))
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"\n📁 {item.Directory}/");
Console.ResetColor();
}
currentDir = item.Directory;
}
string indent = string.IsNullOrEmpty(item.Directory) ? "" : " ";
string? filename = item.FileName;
long uncompressedSize = item.Entry.Size;
long compressedSize = item.Entry.CompressedSize;
double ratio = 0;
if (uncompressedSize > 0)
ratio = (1 - (double)compressedSize / uncompressedSize) * 100;
Console.Write($"{indent}📄 ");
if (string.IsNullOrEmpty(indent))
Console.Write($"{filename,-33}");
else
Console.Write($"{filename,-30}");
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write($"{FormatSize(uncompressedSize),-13}");
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write($"{FormatSize(compressedSize),-13}");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"{ratio:F1}%");
Console.ResetColor();
}
Console.WriteLine(new string('─', 70));
Console.Write($"{" Total",-36}");
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write($"{FormatSize(totalSize),-13}");
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write($"{FormatSize(totalCompressed),-13}");
double totalRatio = totalSize > 0 ? (1 - (double)totalCompressed / totalSize) * 100 : 0;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"{totalRatio:F1}%");
Console.ResetColor();
}
static void ReadFileFromArchive(string archivePath, string filePathInArchive)
{
using var archive = ArchiveFactory.Open(archivePath);
var entry = archive.Entries.FirstOrDefault(e =>
e.Key?.Equals(filePathInArchive, StringComparison.OrdinalIgnoreCase) ?? false)
?? throw new FileNotFoundException($"{filePathInArchive} not found in archive.");
using var reader = new StreamReader(entry.OpenEntryStream());
Console.WriteLine($" {Path.GetFileName(filePathInArchive)}");
Console.WriteLine(new string('─', 70));
Console.WriteLine(reader.ReadToEnd());
Console.WriteLine(new string('─', 70));
}
#endregion
#region Modify archive
static void WriteFileToArchive(string archivePath, string filePathInArchive)
{
if (!File.Exists(filePathInArchive))
throw new FileNotFoundException("Input file does not exist.");
using var archive = ArchiveFactory.Open(archivePath);
if (archive is IWritableArchive writable)
{
writable.AddEntry(Path.GetFileName(filePathInArchive), filePathInArchive);
string tempFile = archivePath + ".tmp";
writable.SaveTo(tempFile, DetectCompressionType(archive));
archive.Dispose();
File.Move(tempFile, archivePath, true);
Console.WriteLine("\n File added to archive.");
}
else
{
throw new NotSupportedException("This is a read-only archive.");
}
}
static void DeleteFileFromArchive(string archivePath, string filePathInArchive)
{
using var archive = ArchiveFactory.Open(archivePath);
if (archive is IWritableArchive writable)
{
var entry = archive.Entries.FirstOrDefault(e =>
e.Key?.Equals(filePathInArchive, StringComparison.OrdinalIgnoreCase) ?? false)
?? throw new FileNotFoundException($"{filePathInArchive} not found in archive.");
writable.RemoveEntry(entry);
string tempFile = archivePath + ".tmp";
writable.SaveTo(tempFile, DetectCompressionType(archive));
archive.Dispose();
File.Move(tempFile, archivePath, true);
Console.WriteLine("\n File removed from archive.");
}
else
{
throw new NotSupportedException("This is a read-only archive.");
}
}
#endregion
#region Helper functions
static string GetInput(string prompt)
{
Console.Write(prompt);
string input = Console.ReadLine()?.Trim() ?? "";
Console.WriteLine();
return input;
}
static string FormatSize(long bytes)
{
string[] sizes = ["B", "KB", "MB", "GB"];
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len /= 1024;
}
return $"{len:0.##} {sizes[order]}";
}
static CompressionType DetectCompressionType(IArchive archive)
{
return archive.Entries.FirstOrDefault(e => !e.IsDirectory)?.CompressionType
?? CompressionType.Deflate;
}
#endregion
}
Help support the channel
' AZUL CODING ---------------------------------------
' .NET C#/VB - Read & Write Compressed Files
' https://youtu.be/vbSbi196s58
Imports System
Imports System.IO
Imports SharpCompress.Archives
Imports SharpCompress.Common
Module Program
Sub Main(args As String())
' Install the SharpCompress package first:
' dotnet add package SharpCompress
Dim running As Boolean = True
While running
Console.WriteLine(vbLf & " Archive manager")
Console.WriteLine(New String("─"c, 70))
Console.WriteLine(" 1. Create archive from folder")
Console.WriteLine(" 2. Extract archive")
Console.WriteLine(" 3. Display archive contents")
Console.WriteLine(" 4. Read file from archive")
Console.WriteLine(" 5. Add file to archive")
Console.WriteLine(" 6. Remove file from archive")
Console.WriteLine(" 7. Exit")
Console.WriteLine(New String("─"c, 70))
Dim choice As String = GetInput(" Enter your choice >> ")
Try
Select Case choice
Case "1"
CreateArchiveFromFolder(GetInput(" Enter folder path >> "))
Case "2"
ExtractArchive(GetInput(" Enter archive path >> "))
Case "3"
DisplayArchiveContents(GetInput(" Enter archive path >> "))
Case "4"
ReadFileFromArchive(
GetInput(" Enter archive path >> "),
GetInput(" Enter filename to read >> ")
)
Case "5"
WriteFileToArchive(
GetInput(" Enter archive path >> "),
GetInput(" Enter filename to add >> ")
)
Case "6"
DeleteFileFromArchive(
GetInput(" Enter archive path >> "),
GetInput(" Enter filename to remove >> ")
)
Case "7"
running = False
Case Else
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine(" Invalid choice. Please try again.")
Console.ResetColor()
Continue While
End Select
If running Then
Console.WriteLine(vbLf & " Press any key to continue...")
Console.ReadKey()
End If
Catch ex As Exception
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine($"{vbLf} Error: {ex.Message}")
Console.ResetColor()
Console.WriteLine(vbLf & " Press any key to continue...")
Console.ReadKey()
End Try
End While
End Sub
#Region "Extract and compress"
Sub CreateArchiveFromFolder(folderPath As String)
If Not Directory.Exists(folderPath) Then
Throw New DirectoryNotFoundException("Folder does not exist.")
End If
Dim dest As String = $"{folderPath}.zip"
Using archive = ArchiveFactory.Create(ArchiveType.Zip)
archive.AddAllFromDirectory(folderPath)
archive.SaveTo(dest, CompressionType.Deflate)
End Using
Console.WriteLine($"{vbLf} Archive created: {dest}")
End Sub
Sub ExtractArchive(archivePath As String)
Using archive = ArchiveFactory.Open(archivePath)
Dim destDir As String = Path.Combine(
If(Path.GetDirectoryName(archivePath), ""),
Path.GetFileNameWithoutExtension(archivePath)
)
Directory.CreateDirectory(destDir)
For Each entry In archive.Entries.Where(Function(e) Not e.IsDirectory)
entry.WriteToDirectory(destDir, New ExtractionOptions With {
.ExtractFullPath = True,
.Overwrite = True
})
Next
Console.WriteLine($"{vbLf} Extracted to folder: {destDir}")
End Using
End Sub
#End Region
#Region "Read contents"
Sub DisplayArchiveContents(archivePath As String)
Using archive = ArchiveFactory.Open(archivePath)
Dim entries As List(Of IArchiveEntry) = archive.Entries.Where(Function(e) Not e.IsDirectory).ToList()
Console.WriteLine(
$"{vbLf} {Path.GetFileName(archivePath)} • {archive.Type} • Total files: {entries.Count}"
)
Console.WriteLine(New String("─"c, 70))
Console.WriteLine($"{" Filename",-35} {"Size",-12} {"Compressed",-12} Ratio")
Console.WriteLine(New String("─"c, 70))
Dim totalSize As Long = 0
Dim totalCompressed As Long = 0
Dim groupedEntries = entries _
.Select(Function(e) New With {
.Entry = e,
.Directory = If(Path.GetDirectoryName(e.Key)?.Replace("\", "/"), ""),
.FileName = Path.GetFileName(e.Key)
}) _
.OrderBy(Function(e) e.Directory) _
.ThenBy(Function(e) e.FileName) _
.ToList()
Dim currentDir As String = Nothing
For Each item In groupedEntries
totalSize += item.Entry.Size
totalCompressed += item.Entry.CompressedSize
If item.Directory <> currentDir Then
If Not String.IsNullOrEmpty(item.Directory) Then
Console.ForegroundColor = ConsoleColor.Blue
Console.WriteLine($"{vbLf}📁 {item.Directory}/")
Console.ResetColor()
End If
currentDir = item.Directory
End If
Dim indent As String = If(String.IsNullOrEmpty(item.Directory), "", " ")
Dim filename As String = item.FileName
Dim uncompressedSize As Long = item.Entry.Size
Dim compressedSize As Long = item.Entry.CompressedSize
Dim ratio As Double = 0
If uncompressedSize > 0 Then
ratio = (1 - CDbl(compressedSize) / uncompressedSize) * 100
End If
Console.Write($"{indent}📄 ")
If String.IsNullOrEmpty(indent) Then
Console.Write($"{filename,-33}")
Else
Console.Write($"{filename,-30}")
End If
Console.ForegroundColor = ConsoleColor.Cyan
Console.Write($"{FormatSize(uncompressedSize),-13}")
Console.ForegroundColor = ConsoleColor.Magenta
Console.Write($"{FormatSize(compressedSize),-13}")
Console.ForegroundColor = ConsoleColor.Yellow
Console.WriteLine($"{ratio:F1}%")
Console.ResetColor()
Next
Console.WriteLine(New String("─"c, 70))
Console.Write($"{" Total",-36}")
Console.ForegroundColor = ConsoleColor.Cyan
Console.Write($"{FormatSize(totalSize),-13}")
Console.ForegroundColor = ConsoleColor.Magenta
Console.Write($"{FormatSize(totalCompressed),-13}")
Dim totalRatio As Double = If(totalSize > 0, (1 - CDbl(totalCompressed) / totalSize) * 100, 0)
Console.ForegroundColor = ConsoleColor.Yellow
Console.WriteLine($"{totalRatio:F1}%")
Console.ResetColor()
End Using
End Sub
Sub ReadFileFromArchive(archivePath As String, filePathInArchive As String)
Using archive = ArchiveFactory.Open(archivePath)
Dim entry = archive.Entries.FirstOrDefault(Function(e) _
If(e.Key?.Equals(filePathInArchive, StringComparison.OrdinalIgnoreCase), False))
If entry Is Nothing Then
Throw New FileNotFoundException($"{filePathInArchive} not found in archive.")
End If
Using reader As New StreamReader(entry.OpenEntryStream())
Console.WriteLine($" {Path.GetFileName(filePathInArchive)}")
Console.WriteLine(New String("─"c, 70))
Console.WriteLine(reader.ReadToEnd())
Console.WriteLine(New String("─"c, 70))
End Using
End Using
End Sub
#End Region
#Region "Modify archive"
Sub WriteFileToArchive(archivePath As String, filePathInArchive As String)
If Not File.Exists(filePathInArchive) Then
Throw New FileNotFoundException("Input file does not exist.")
End If
Using archive = ArchiveFactory.Open(archivePath)
Dim writable = TryCast(archive, IWritableArchive)
If writable IsNot Nothing Then
writable.AddEntry(Path.GetFileName(filePathInArchive), filePathInArchive)
Dim tempFile As String = archivePath & ".tmp"
writable.SaveTo(tempFile, DetectCompressionType(archive))
archive.Dispose()
File.Move(tempFile, archivePath, True)
Console.WriteLine(vbLf & " File added to archive.")
Else
Throw New NotSupportedException("This is a read-only archive.")
End If
End Using
End Sub
Sub DeleteFileFromArchive(archivePath As String, filePathInArchive As String)
Using archive = ArchiveFactory.Open(archivePath)
Dim writable = TryCast(archive, IWritableArchive)
If writable IsNot Nothing Then
Dim entry = archive.Entries.FirstOrDefault(Function(e) _
If(e.Key?.Equals(filePathInArchive, StringComparison.OrdinalIgnoreCase), False))
If entry Is Nothing Then
Throw New FileNotFoundException($"{filePathInArchive} not found in archive.")
End If
writable.RemoveEntry(entry)
Dim tempFile As String = archivePath & ".tmp"
writable.SaveTo(tempFile, DetectCompressionType(archive))
archive.Dispose()
File.Move(tempFile, archivePath, True)
Console.WriteLine(vbLf & " File removed from archive.")
Else
Throw New NotSupportedException("This is a read-only archive.")
End If
End Using
End Sub
#End Region
#Region "Helper functions"
Function GetInput(prompt As String) As String
Console.Write(prompt)
Dim input As String = If(Console.ReadLine()?.Trim(), "")
Console.WriteLine()
Return input
End Function
Function FormatSize(bytes As Long) As String
Dim sizes() As String = {"B", "KB", "MB", "GB"}
Dim len As Double = bytes
Dim order As Integer = 0
While len >= 1024 AndAlso order < sizes.Length - 1
order += 1
len /= 1024
End While
Return $"{len:0.##} {sizes(order)}"
End Function
Function DetectCompressionType(archive As IArchive) As CompressionType
Dim entry = archive.Entries.FirstOrDefault(Function(e) Not e.IsDirectory)
Return If(entry?.CompressionType, CompressionType.Deflate)
End Function
#End Region
End Module


