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: Resources 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 Resources directory:
Resources/
├── message.json
├── config.txt
└── template.html
The resources will be automatically packed into a .dat file during build.
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: Resources) -->
<ResourcePackerDirectory>Resources</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