LuYao.ResourcePacker is a .NET library for packaging and accessing resource files during build time and runtime.
- Pack multiple resource files into a single .dat file during build
- Intelligent tiered compression with GZip - automatic compression with sampling for optimal space/performance
- Directory-based resource scanning (default: Attachments directory)
- MSBuild integration
- Simple runtime API for resource access
- Async support
- Configurable through MSBuild properties
- C# Source Generator for strongly-typed resource access with fixed "R" class (Android-style)
Install-Package LuYao.ResourcePacker.MSBuild
Install-Package LuYao.ResourcePacker
dotnet add package LuYao.ResourcePacker.MSBuild
dotnet add package LuYao.ResourcePackerPlace your resource files in the Attachments directory:
Attachments/
├── message.json
├── config.txt
└── template.html
The resources will be automatically packed into a .dat file during build.
Note: The default directory was changed from
ResourcestoAttachmentsto avoid conflicts with C# .resx files, which typically use theResourcesdirectory. If you prefer to useResourcesor any other directory name, you can configure it in your .csproj file (see Configuration section below).
Access resources at runtime using the ResourcePackageReader:
using LuYao.ResourcePacker;
// Read resources
using var reader = new ResourcePackageReader("YourAssembly.dat");
// Read as string
string content = await reader.ReadResourceAsStringAsync("message");
// Read as bytes
byte[] data = await reader.ReadResourceAsync("config");
// List all resources
foreach (var key in reader.ResourceKeys)
{
Console.WriteLine(key);
}The source generator automatically creates an internal static class named R (Android-style) in the project's root namespace with strongly-typed access to your resources:
using LuYao.ResourcePacker;
using YourAssembly; // Import the namespace where the generated class resides
// Access resource keys as constants
Console.WriteLine(R.Keys.message);
Console.WriteLine(R.Keys.config);
Console.WriteLine(R.Keys.template);
// Read resources using generated methods
string message = await R.ReadMessageAsStringAsync();
byte[] configBytes = await R.ReadConfigAsync();
string template = await R.ReadTemplateAsStringAsync();
// Access the underlying reader if needed
ResourcePackageReader reader = R.Reader;Benefits of the Strongly-Typed API:
- IntelliSense support for resource names
- Compile-time checking of resource names
- No magic strings in your code
- Auto-generated documentation comments
- Simple, consistent "R" class name across all projects
In your .csproj file:
<PropertyGroup>
<!-- Enable/disable resource packing -->
<ResourcePackerEnabled>true</ResourcePackerEnabled>
<!-- Custom resource directory (default: Attachments) -->
<ResourcePackerDirectory>Attachments</ResourcePackerDirectory>
<!-- Custom output filename -->
<ResourcePackerOutputFileName>$(AssemblyName).dat</ResourcePackerOutputFileName>
</PropertyGroup>LuYao.ResourcePacker includes intelligent tiered compression to optimize package size while maintaining fast access:
Resources are automatically compressed using GZip based on these rules:
- Files < 255 bytes: Not compressed (overhead exceeds benefit)
- Files 255 bytes - 4KB: Full file compression attempted, only applied if compression ratio ≥ 5%
- Files > 4KB: First 8KB sampled for compression evaluation, full file compressed if sample ratio ≥ 5%
- Already compressed formats: Automatically skipped (jpg, png, zip, mp3, mp4, pdf, fonts, etc.)
- Automatic: No configuration needed - compression decisions made intelligently during build
- Transparent: Decompression happens automatically when reading resources
- Efficient: Typical 50-80% size reduction for compressible content (text, JSON, XML, source code)
- Smart: Avoids compressing already-compressed formats and small files
- Compression algorithm: GZip
- Minimum compression ratio: 5%
- Streaming decompression: Large compressed resources can be streamed without loading entire content into memory
- Thread-safe: Concurrent access to compressed resources is fully supported
The compression is completely transparent to your code - no API changes required.
When you add resource files (e.g., test.txt, config.json) to your Resources directory:
- During build, the MSBuild task scans all files in the
Resourcesdirectory - These files are packaged into a
.datfile - The source generator creates an internal static class named
Rin the project's root namespace (defaults to assembly name) with:- A nested
Keysclass containing const strings for each resource (filename without extension) - A static
Readerproperty providing access to theResourcePackageReader - Strongly-typed methods like
ReadTestAsync()andReadConfigAsync()
- A nested
- Resource keys are generated from filenames (without extension), with invalid C# identifier characters replaced by underscores
Example generated code:
namespace YourAssembly
{
internal static class R
{
public static class Keys
{
public const string test = "test";
public const string config = "config";
}
public static ResourcePackageReader Reader { get; }
public static Task<byte[]> ReadTestAsync() { ... }
public static Task<string> ReadTestAsStringAsync() { ... }
public static Task<byte[]> ReadConfigAsync() { ... }
public static Task<string> ReadConfigAsStringAsync() { ... }
}
}dotnet builddotnet testThis project is licensed under the MIT License - see the LICENSE file for details.
Created by Soar360 on 2025-10-25