BugFree.FileStorage 1.2.2026.623-beta1157

This is a prerelease version of BugFree.FileStorage.
dotnet add package BugFree.FileStorage --version 1.2.2026.623-beta1157
                    
NuGet\Install-Package BugFree.FileStorage -Version 1.2.2026.623-beta1157
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BugFree.FileStorage" Version="1.2.2026.623-beta1157" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BugFree.FileStorage" Version="1.2.2026.623-beta1157" />
                    
Directory.Packages.props
<PackageReference Include="BugFree.FileStorage" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BugFree.FileStorage --version 1.2.2026.623-beta1157
                    
#r "nuget: BugFree.FileStorage, 1.2.2026.623-beta1157"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BugFree.FileStorage@1.2.2026.623-beta1157
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BugFree.FileStorage&version=1.2.2026.623-beta1157&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=BugFree.FileStorage&version=1.2.2026.623-beta1157&prerelease
                    
Install as a Cake Tool

BugFree.FileStorage

一个面向 .NET 的通用文件存储库,统一封装阿里云 OSS、腾讯云 COS、MinIO 和本地文件系统的对象存储能力。

License: MIT NuGet


✨ 核心特性

  • 多 Provider 统一 API — 通过 FileStorageService 统一操作 OSS / COS / MinIO / 本地文件系统,切换存储后端只需修改配置
  • 分片上传 — 支持大文件分片上传(Initiate → UploadPart → Complete),内置并发控制与序号校验
  • 预签名 URL — 为云端 Provider 生成可访问的预签名 URL,本地 Provider 返回安全签名参数(HMAC 验证,避免路径泄露)
  • 智能磁盘选择 — 本地存储支持多磁盘/多根路径,可选顺序、剩余空间优先、随机策略
  • 本地索引 — 支持落盘索引(FileIndex)和字符串索引(StringIndex),加速 bucket+key → disk 映射,自动修复脏索引
  • 多目标框架 — 支持 .NET 8.0 和 .NET 10.0
  • 配置驱动 — 集成 NewLife.Configuration,支持加密存储、热重载

📦 安装

dotnet add package BugFree.FileStorage

🚀 快速开始

1. 注册服务

builder.Services.AddFileStorageService();

2. 配置存储(appsettings.json)

{
  "FileStorage": {
    "ProviderType": "Minio",
    "SingleFileMaxSize": 209715200,
    "AliyunOss": {
      "Endpoint": "oss-cn-hangzhou.aliyuncs.com",
      "AccessKeyId": "<your-access-key-id>",
      "AccessKeySecret": "<your-access-key-secret>",
      "BucketName": "my-bucket"
    },
    "TencentCos": {
      "SecretId": "<your-secret-id>",
      "SecretKey": "<your-secret-key>",
      "BucketName": "my-bucket-1234567890",
      "Region": "ap-guangzhou"
    },
    "Minio": {
      "Endpoint": "192.168.1.100:9000",
      "AccessKey": "minioadmin",
      "SecretKey": "minioadmin",
      "BucketName": "my-bucket",
      "EnableHttps": false
    },
    "Local": {
      "StoragePath": ["D:\\FileStorage", "E:\\FileStorage"],
      "SelectPolicy": "FreeSpaceFirst",
      "SignedUrlExpireSeconds": 3600,
      "FileIndexType": "String"
    }
  }
}

3. 使用

[ApiController]
public class FileController : ControllerBase
{
    private readonly FileStorageService _fileStorage;

    public FileController(FileStorageService fileStorage)
    {
        _fileStorage = fileStorage;
    }

    // 上传文件
    [HttpPost("upload")]
    public async Task<IActionResult> Upload(IFormFile file)
    {
        using var stream = file.OpenReadStream();
        var info = await _fileStorage.UploadAsync(file.FileName, stream, file.Length, file.ContentType);
        return Ok(info);
    }

    // 下载文件
    [HttpGet("download/{bucket}/{key}")]
    public async Task<IActionResult> Download(string bucket, string key)
    {
        var stream = await _fileStorage.GetAsync(StorageProviderType.Minio, bucket, key);
        if (stream == null) return NotFound();
        return File(stream, "application/octet-stream");
    }

    // 生成预签名 URL
    [HttpGet("presigned/{bucket}/{key}")]
    public async Task<IActionResult> Presigned(string bucket, string key)
    {
        var result = await _fileStorage.GeneratePresignedUrlAsync(StorageProviderType.Minio, bucket, key, TimeSpan.FromHours(1));
        return Ok(result);
    }

    // 删除文件
    [HttpDelete("delete/{bucket}/{key}")]
    public async Task<IActionResult> Delete(string bucket, string key)
    {
        await _fileStorage.DeleteAsync(StorageProviderType.Minio, bucket, key);
        return Ok();
    }
}

4. 分片上传大文件

// 初始化分片
var context = await _fileStorage.InitiateMultipartUploadAsync("my-bucket", "large-file.bin");

// 分片上传(每个分片独立处理)
for (int i = 0; i < chunks.Length; i++)
{
    using var stream = new MemoryStream(chunks[i]);
    var result = await _fileStorage.UploadPartAsync(context, i + 1, stream, chunks[i].Length);
}

// 完成分片上传
var info = await _fileStorage.CompleteMultipartUploadAsync(context, results);

📂 项目结构

BugFree.FileStorage/
├── BugFree.FileStorage/                    # 核心库
│   ├── Abstractions/                       # 抽象定义
│   │   ├── IFileStorageProvider.cs         #   Provider 内部抽象
│   │   ├── FileObjectInfo.cs               #   文件对象信息
│   │   ├── PresignedUrlResult.cs           #   预签名结果
│   │   └── MultipartUploadContext.cs       #   分片上传上下文
│   ├── Provider/                           # 存储实现
│   │   ├── AliCloud/AliyunOssFileStorageProvider.cs   # 阿里云 OSS
│   │   ├── TencentCloud/TencentCosFileStorageProvider.cs  # 腾讯云 COS
│   │   ├── Minio/MinioFileStorageProvider.cs          # MinIO
│   │   └── Local/                          # 本地文件系统
│   │       ├── LocalFileStorageProvider.cs
│   │       ├── LocalFileStorageSetting.cs
│   │       ├── DiskSelector/              # 磁盘选择策略
│   │       │   ├── LocalDiskSelectorBase.cs
│   │       │   ├── SequentialDiskSelector.cs
│   │       │   ├── FreeSpaceFirstDiskSelector.cs
│   │       │   └── RandomDiskSelector.cs
│   │       └── Index/                     # 索引实现
│   │           ├── IIndex.cs
│   │           ├── FileIndex.cs
│   │           └── StringIndex.cs
│   ├── FileStorageService.cs               # 统一入口
│   ├── FileStorageSetting.cs               # 配置
│   ├── StorageProviderType.cs              # 枚举
│   └── ServiceCollectionExtensions.cs      # DI 注册
├── BugFree.FileStorage.TestProject/        # 单元测试
├── Directory.Build.props                   # 全局 MSBuild 属性
└── Directory.Build.targets                 # 全局 MSBuild 目标

🔧 配置详解

全局配置

属性 类型 默认值 说明
ProviderType StorageProviderType Local 存储类型
SingleFileMaxSize Int64 200MB 单文件直接上传上限,超过需分片
MultipartSize Int32 64MB 分片上传最小分片大小
MultipartConcurrency int 4 分片上传最大并发数
MultipartMaxCount int 200 分片上传最大分片数

本地存储

属性 类型 默认值 说明
StoragePath IList<string> 存储根路径列表
SelectPolicy DiskSelectPolicy FreeSpaceFirst 磁盘选择策略
SignedUrlExpireSeconds Int32 3600 预签名 URL 有效期(秒)
FileIndexType FileIndexType String 文件索引类型
ParamEncryptKey string 随机 签名加密密钥

磁盘选择策略

策略 说明 适用场景
Sequential 按配置顺序循环选择 磁盘空间均匀分配
FreeSpaceFirst 选择剩余空间最大的磁盘(默认) 通用场景
Random 随机选择 负载均衡,分散 I/O

索引类型

类型 说明 特点
File 落盘索引(文件存储) 快速定位,进程重启可恢复
String 字符串索引(diskId 嵌入 bucket) 不落盘,零维护

🛡️ 安全设计

  • 路径安全 — 上传和删除时使用 PathSecurityHelper 校验 bucket/key,防止路径穿越攻击
  • 预签名安全 — 本地存储使用 HMAC-MD5 签名({bucket}:{key}:{expireAt}),避免泄露真实本地路径
  • 文件唯一性 — 上传使用 CreateNew 模式,防止同名文件被意外覆盖
  • 内容长度校验 — 对可 Seek 流强校验 contentLength,避免截断或合并异常

📝 本地存储预签名流程

本地存储不直接返回可访问 URL,采用签名参数模式:

1. 生成签名: {bucket}:{key}:{expireAtUnixSeconds} → HMAC-MD5 → sign
2. 返回 Query: { expireAt, sign }
3. 客户端请求: GET /api/download/{bucket}/{key}?expireAt=xxx&sign=xxx
4. 服务端验证: 检查 expireAt 未过期 + HMAC 签名匹配
5. 验证通过: 读取本地文件并返回

🧪 测试

cd BugFree.FileStorage.TestProject
dotnet test

📄 License

MIT License — Copyright (c) 2024 IoTHub 开发团队


🌐 English

See README.en.md for the English version.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.2026.623-beta1157 40 6/23/2026
1.1.2026.325-beta1128 78 3/25/2026
1.1.2026.325-beta1042 53 3/25/2026
1.1.2026.325-beta1036 52 3/25/2026
1.1.2026.325-beta1013 57 3/25/2026
1.1.2026.303-beta1510 66 3/3/2026
1.1.2026.127-beta1557 70 3/3/2026
1.1.2026.115-beta1541 85 1/15/2026
1.0.2026.107-beta1426 77 1/7/2026
1.0.2026.106-beta1144 74 1/6/2026
1.0.2025.1224-beta1658 155 12/24/2025
1.0.2025.1224-beta1527 150 12/24/2025
1.0.2025.1224-beta1412 157 12/24/2025