C# Excel开源操作库MiniExcel使用教程

news2025/3/12 22:30:25

简介
MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。

目前主流框架大多需要将数据全载入到内存方便操作,但这会导致内存消耗问题,MiniExcel 尝试以 Stream 角度写底层算法逻辑,能让原本1000多MB占用降低到几MB,避免内存不够情况。

image

特点
低内存耗用,避免OOM、频繁 Full GC 情况
支持即时操作每行数据
兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询
轻量,不需要安装 Microsoft Office、COM+,DLL小于150KB
简便操作的 API 风格
快速开始
导入、读取 Excel
导出 、创建 Excel
模板填充、创建 Excel
Excel Column Name/Index/Ignore Attribute
例子
安装
请查看 NuGet

更新日志
请查看 Release Notes

TODO
请查看 TODO

性能比较、测试
Benchmarks 逻辑可以在 MiniExcel.Benchmarks 查看或是提交 PR,运行指令

dotnet run -p .\benchmarks\MiniExcel.Benchmarks\ -c Release -f netcoreapp3.1 – -f * --join

最后一次运行规格、结果 :

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
[Host] : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
Job-ZYYABG : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
IterationCount=3 LaunchCount=3 WarmupCount=3

Benchmark History : Link

导入、查询 Excel 比较
逻辑 : 以 Test1,000,000x10.xlsx 做基准与主流框架做性能测试,总共 1,000,000 行 * 10 列笔 “HelloWorld”,文件大小 23 MB

Library Method 最大内存耗用 平均时间
MiniExcel ‘MiniExcel QueryFirst’ 0.109 MB 0.0007264 sec
ExcelDataReader ‘ExcelDataReader QueryFirst’ 15.24 MB 10.66421 sec
MiniExcel ‘MiniExcel Query’ 17.3 MB 14.17933 sec
ExcelDataReader ‘ExcelDataReader Query’ 17.3 MB 22.56508 sec
Epplus ‘Epplus QueryFirst’ 1,452 MB 18.19801 sec
Epplus ‘Epplus Query’ 1,451 MB 23.64747 sec
OpenXmlSDK ‘OpenXmlSDK Query’ 1,412 MB 52.00327 sec
OpenXmlSDK ‘OpenXmlSDK QueryFirst’ 1,413 MB 52.34865 sec
ClosedXml ‘ClosedXml QueryFirst’ 2,158 MB 66.18897 sec
ClosedXml ‘ClosedXml Query’ 2,184 MB 191.43412 sec
导出、创建 Excel 比较
逻辑 : 创建1千万笔 “HelloWorld”

Library Method 最大内存耗用 平均时间
MiniExcel ‘MiniExcel Create Xlsx’ 15 MB 11.53181 sec
Epplus ‘Epplus Create Xlsx’ 1,204 MB 22.50971 sec
OpenXmlSdk ‘OpenXmlSdk Create Xlsx’ 2,621 MB 42.47399 sec
ClosedXml ‘ClosedXml Create Xlsx’ 7,141 MB 140.93992 sec
读/导入 Excel

  1. Query 查询 Excel 返回强型别 IEnumerable 数据 [Try it]
    public class UserAccount
    {
    public Guid ID { get; set; }
    public string Name { get; set; }
    public DateTime BoD { get; set; }
    public int Age { get; set; }
    public bool VIP { get; set; }
    public decimal Points { get; set; }
    }

var rows = MiniExcel.Query(path);

// or

using (var stream = File.OpenRead(path))
var rows = stream.Query();

image

  1. Query 查询 Excel 返回Dynamic IEnumerable 数据 [Try it]
    Key 系统预设为 A,B,C,D…Z
    MiniExcel 1
    Github 2
    var rows = MiniExcel.Query(path).ToList();

// or
using (var stream = File.OpenRead(path))
{
var rows = stream.Query().ToList();

Assert.Equal("MiniExcel", rows[0].A);
Assert.Equal(1, rows[0].B);
Assert.Equal("Github", rows[1].A);
Assert.Equal(2, rows[1].B);

}

  1. 查询数据以第一行数据当Key [Try it]
    注意 : 同名以右边数据为准

Input Excel :

Column1 Column2
MiniExcel 1
Github 2
var rows = MiniExcel.Query(useHeaderRow:true).ToList();

// or

using (var stream = File.OpenRead(path))
{
var rows = stream.Query(useHeaderRow:true).ToList();

Assert.Equal("MiniExcel", rows[0].Column1);
Assert.Equal(1, rows[0].Column2);
Assert.Equal("Github", rows[1].Column1);
Assert.Equal(2, rows[1].Column2);

}

  1. Query 查询支援延迟加载(Deferred Execution),能配合LINQ First/Take/Skip办到低消耗、高效率复杂查询
    举例 : 查询第一笔数据

var row = MiniExcel.Query(path).First();
Assert.Equal(“HelloWorld”, row.A);

// or

using (var stream = File.OpenRead(path))
{
var row = stream.Query().First();
Assert.Equal(“HelloWorld”, row.A);
}

与其他框架效率比较 :

queryfirst

  1. 查询指定 Sheet 名称
    MiniExcel.Query(path, sheetName: “SheetName”);
    //or
    stream.Query(sheetName: “SheetName”);

  2. 查询所有 Sheet 名称跟数据
    var sheetNames = MiniExcel.GetSheetNames(path);
    foreach (var sheetName in sheetNames)
    {
    var rows = MiniExcel.Query(path, sheetName: sheetName);
    }

  3. 查询所有栏(列)
    var columns = MiniExcel.GetColumns(path); // e.g result : [“A”,“B”…]

or

var columns = MiniExcel.GetColumns(path, useHeaderRow: true);
// e.g result : [“excel表实际的列名称”,“excel表实际的列名称”…]

var cnt = columns.Count; // get column count

  1. Dynamic Query 转成 IDictionary<string,object> 数据
    foreach(IDictionary<string,object> row in MiniExcel.Query(path))
    {
    //…
    }

// or
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();

  1. Query 读 Excel 返回 DataTable
    提醒 : 不建议使用,因为DataTable会将数据全载入内存,失去MiniExcel低内存消耗功能。

var table = MiniExcel.QueryAsDataTable(path, useHeaderRow: true);

image

  1. 指定单元格开始读取数据
    MiniExcel.Query(path,useHeaderRow:true,startCell:“B3”)

image

  1. 合并的单元格填充
    注意 : 效率相对于没有使用合并填充来说差
    底层原因 : OpenXml 标准将 mergeCells 放在文件最下方,导致需要遍历两次 sheetxml

    var config = new OpenXmlConfiguration()
    {
    FillMergedCells = true
    };
    var rows = MiniExcel.Query(path, configuration: config);

image

支持不固定长宽多行列填充

image

  1. 读取大文件硬盘缓存 (Disk-Base Cache - SharedString)
    概念 : MiniExcel 当判断文件 SharedString 大小超过 5MB,预设会使用本地缓存,如 10x100000.xlsx(一百万笔数据),读取不开启本地缓存需要最高内存使用约195MB,开启后降为65MB。但要特别注意,此优化是以时间换取内存减少,所以读取效率会变慢,此例子读取时间从 7.4 秒提高到 27.2 秒,假如不需要能用以下代码关闭硬盘缓存

var config = new OpenXmlConfiguration { EnableSharedStringCache = false };
MiniExcel.Query(path,configuration: config)

也能使用 SharedStringCacheSize 调整 sharedString 文件大小超过指定大小才做硬盘缓存

var config = new OpenXmlConfiguration { SharedStringCacheSize=50010241024 };
MiniExcel.Query(path, configuration: config);

image

image

写/导出 Excel
必须是非abstract 类别有公开无参数构造函数
MiniExcel SaveAs 支援 IEnumerable参数延迟查询,除非必要请不要使用 ToList 等方法读取全部数据到内存
图片 : 是否呼叫 ToList 的内存差别

image1. 支持集合<匿名类别>或是<强型别> [Try it]
var path = Path.Combine(Path.GetTempPath(), $“{Guid.NewGuid()}.xlsx”);
MiniExcel.SaveAs(path, new[] {
new { Column1 = “MiniExcel”, Column2 = 1 },
new { Column1 = “Github”, Column2 = 2}
});

  1. IEnumerable<IDictionary<string, object>>
    var values = new List<Dictionary<string, object>>()
    {
    new Dictionary<string,object>{{ “Column1”, “MiniExcel” }, { “Column2”, 1 } },
    new Dictionary<string,object>{{ “Column1”, “Github” }, { “Column2”, 2 } }
    };
    MiniExcel.SaveAs(path, values);

output :

Column1 Column2
MiniExcel 1
Github 2
3. IDataReader
推荐使用,可以避免载入全部数据到内存
MiniExcel.SaveAs(path, reader);

image

推荐 DataReader 多表格导出方式(建议使用 Dapper ExecuteReader )

using (var cnn = Connection)
{
cnn.Open();
var sheets = new Dictionary<string,object>();
sheets.Add(“sheet1”, cnn.ExecuteReader(“select 1 id”));
sheets.Add(“sheet2”, cnn.ExecuteReader(“select 2 id”));
MiniExcel.SaveAs(“Demo.xlsx”, sheets);
}

  1. Datatable
    不推荐使用,会将数据全载入内存
    优先使用 Caption 当栏位名称
    var path = Path.Combine(Path.GetTempPath(), $“{Guid.NewGuid()}.xlsx”);
    var table = new DataTable();
    {
    table.Columns.Add(“Column1”, typeof(string));
    table.Columns.Add(“Column2”, typeof(decimal));
    table.Rows.Add(“MiniExcel”, 1);
    table.Rows.Add(“Github”, 2);
    }

MiniExcel.SaveAs(path, table);

  1. Dapper Query
    不推荐使用,会将数据全载入内存,建议使用ExecuteReader
    using (var connection = GetConnection(connectionString))
    {
    var rows = connection.Query(@“select ‘MiniExcel’ as Column1,1 as Column2 union all select ‘Github’,2”);
    MiniExcel.SaveAs(path, rows);
    }

  2. SaveAs 支持 Stream,生成文件不落地 [Try it]
    using (var stream = new MemoryStream()) //支持 FileStream,MemoryStream…等
    {
    stream.SaveAs(values);
    }

像是 API 导出 Excel

public IActionResult DownloadExcel()
{
var values = new[] {
new { Column1 = “MiniExcel”, Column2 = 1 },
new { Column1 = “Github”, Column2 = 2}
};

var memoryStream = new MemoryStream();
memoryStream.SaveAs(values);
memoryStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
    FileDownloadName = "demo.xlsx"
};

}

  1. 创建多个工作表(Sheet)
    // 1. Dictionary<string,object>
    var users = new[] { new { Name = “Jack”, Age = 25 }, new { Name = “Mike”, Age = 44 } };
    var department = new[] { new { ID = “01”, Name = “HR” }, new { ID = “02”, Name = “IT” } };
    var sheets = new Dictionary<string, object>
    {
    [“users”] = users,
    [“department”] = department
    };
    MiniExcel.SaveAs(path, sheets);

// 2. DataSet
var sheets = new DataSet();
sheets.Add(UsersDataTable);
sheets.Add(DepartmentDataTable);
//…
MiniExcel.SaveAs(path, sheets);

image

  1. 表格样式选择
    预设样式为

image

不需要样式

var config = new OpenXmlConfiguration()
{
TableStyles = TableStyles.None
};
MiniExcel.SaveAs(path, value,configuration:config);

image

  1. AutoFilter 筛选
    从 0.19.0 支持,可藉由 OpenXmlConfiguration.AutoFilter 设定,预设为True。关闭 AutoFilter 方式 :

MiniExcel.SaveAs(path, value, configuration: new OpenXmlConfiguration() { AutoFilter = false });

  1. 图片生成
    注意 : 目前此功能不支持避免OOM

var value = new[] {
new { Name=“github”,Image=File.ReadAllBytes(PathHelper.GetFile(“images/github_logo.png”))},
new { Name=“google”,Image=File.ReadAllBytes(PathHelper.GetFile(“images/google_logo.png”))},
new { Name=“microsoft”,Image=File.ReadAllBytes(PathHelper.GetFile(“images/microsoft_logo.png”))},
new { Name=“reddit”,Image=File.ReadAllBytes(PathHelper.GetFile(“images/reddit_logo.png”))},
new { Name=“statck_overflow”,Image=File.ReadAllBytes(PathHelper.GetFile(“images/statck_overflow_logo.png”))},
};
MiniExcel.SaveAs(path, value);

image

  1. Byte Array 文件导出
    从 1.22.0 开始,当值类型为 byte[] 系统预设会转成保存文件路径以便导入时转回 byte[],如不想转换可以将 OpenXmlConfiguration.EnableConvertByteArray 改为 false,能提升系统效率。

image

  1. 垂直合并相同的单元格
    只支持 xlsx 格式合并单元格

var mergedFilePath = Path.Combine(Path.GetTempPath(), $“{Guid.NewGuid().ToString()}.xlsx”);

var path = @“…/…/…/…/…/samples/xlsx/TestMergeSameCells.xlsx”;

MiniExcel.MergeSameCells(mergedFilePath, path);

var memoryStream = new MemoryStream();

var path = @“…/…/…/…/…/samples/xlsx/TestMergeSameCells.xlsx”;

memoryStream.MergeSameCells(path);

合并前后对比

before_merge_cells after_merge_cells

  1. 是否写入 null values cell
    预设:

DataTable dt = new DataTable();

/* … */

DataRow dr = dt.NewRow();

dr[“Name1”] = “Somebody once”;
dr[“Name2”] = null;
dr[“Name3”] = “told me.”;

dt.Rows.Add(dr);

MiniExcel.SaveAs(@“C:\temp\Book1.xlsx”, dt);

image

<x:row r=“2”>
<x:c r=“A2” t =“str” s=“2”>
<x:v>Somebody once</x:v>
</x:c>
<x:c r=“B2” t =“str” s=“2”>
<x:v></x:v>
</x:c>
<x:c r=“C2” t =“str” s=“2”>
<x:v>told me.</x:v>
</x:c>
</x:row>

设定不写入:

OpenXmlConfiguration configuration = new OpenXmlConfiguration()
{
EnableWriteNullValueCell = false // Default value is true.
};

MiniExcel.SaveAs(@“C:\temp\Book1.xlsx”, dt, configuration: configuration);

image

<x:row r=“2”>
<x:c r=“A2” t =“str” s=“2”>
<x:v>Somebody once</x:v>
</x:c>
<x:c r=“B2” s=“2”></x:c>
<x:c r=“C2” t =“str” s=“2”>
<x:v>told me.</x:v>
</x:c>
</x:row>

模板填充 Excel
宣告方式类似 Vue 模板 {{变量名称}}, 或是集合渲染 {{集合名称.栏位名称}}
集合渲染支持 IEnumerable/DataTable/DapperRow

  1. 基本填充
    模板:
    image

最终效果:
image

代码:

// 1. By POCO
var value = new
{
Name = “Jack”,
CreateDate = new DateTime(2021, 01, 01),
VIP = true,
Points = 123
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

// 2. By Dictionary
var value = new Dictionary<string, object>()
{
[“Name”] = “Jack”,
[“CreateDate”] = new DateTime(2021, 01, 01),
[“VIP”] = true,
[“Points”] = 123
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

  1. IEnumerable 数据填充
    Note1: 同行从左往右以第一个 IEnumerableUse 当列表来源 (不支持同列多集合)

模板:
image

最终效果:
image

代码:

//1. By POCO
var value = new
{
employees = new[] {
new {name=“Jack”,department=“HR”},
new {name=“Lisa”,department=“HR”},
new {name=“John”,department=“HR”},
new {name=“Mike”,department=“IT”},
new {name=“Neo”,department=“IT”},
new {name=“Loan”,department=“IT”}
}
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

//2. By Dictionary
var value = new Dictionary<string, object>()
{
[“employees”] = new[] {
new {name=“Jack”,department=“HR”},
new {name=“Lisa”,department=“HR”},
new {name=“John”,department=“HR”},
new {name=“Mike”,department=“IT”},
new {name=“Neo”,department=“IT”},
new {name=“Loan”,department=“IT”}
}
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

  1. 复杂数据填充
    Note: 支持多 sheet 填充,并共用同一组参数

模板:

image

最终效果:

image

代码:

// 1. By POCO
var value = new
{
title = “FooCompany”,
managers = new[] {
new {name=“Jack”,department=“HR”},
new {name=“Loan”,department=“IT”}
},
employees = new[] {
new {name=“Wade”,department=“HR”},
new {name=“Felix”,department=“HR”},
new {name=“Eric”,department=“IT”},
new {name=“Keaton”,department=“IT”}
}
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

// 2. By Dictionary
var value = new Dictionary<string, object>()
{
[“title”] = “FooCompany”,
[“managers”] = new[] {
new {name=“Jack”,department=“HR”},
new {name=“Loan”,department=“IT”}
},
[“employees”] = new[] {
new {name=“Wade”,department=“HR”},
new {name=“Felix”,department=“HR”},
new {name=“Eric”,department=“IT”},
new {name=“Keaton”,department=“IT”}
}
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

  1. 大数据填充效率比较
    NOTE: 在 MiniExcel 使用 IEnumerable 延迟 ( 不ToList ) 可以节省内存使用

image

  1. Cell 值自动类别对应
    模板

image

最终效果

image

类别

public class Poco
{
public string @string { get; set; }
public int? @int { get; set; }
public decimal? @decimal { get; set; }
public double? @double { get; set; }
public DateTime? datetime { get; set; }
public bool? @bool { get; set; }
public Guid? Guid { get; set; }
}

代码

var poco = new TestIEnumerableTypePoco { @string = “string”, @int = 123, @decimal = decimal.Parse(“123.45”), @double = (double)123.33, @datetime = new DateTime(2021, 4, 1), @bool = true, @Guid = Guid.NewGuid() };
var value = new
{
Ts = new[] {
poco,
new TestIEnumerableTypePoco{},
null,
poco
}
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

  1. Example : 列出 Github 专案
    模板

image

最终效果

image

代码

var projects = new[]
{
new {Name = “MiniExcel”,Link=“https://github.com/shps951023/MiniExcel”,Star=146, CreateTime=new DateTime(2021,03,01)},
new {Name = “HtmlTableHelper”,Link=“https://github.com/shps951023/HtmlTableHelper”,Star=16, CreateTime=new DateTime(2020,02,01)},
new {Name = “PocoClassGenerator”,Link=“https://github.com/shps951023/PocoClassGenerator”,Star=16, CreateTime=new DateTime(2019,03,17)}
};
var value = new
{
User = “ITWeiHan”,
Projects = projects,
TotalStar = projects.Sum(s => s.Star)
};
MiniExcel.SaveAsByTemplate(path, templatePath, value);

  1. 分组数据填充
    var value = new Dictionary<string, object>()
    {
    [“employees”] = new[] {
    new {name=“Jack”,department=“HR”},
    new {name=“Jack”,department=“HR”},
    new {name=“John”,department=“HR”},
    new {name=“John”,department=“IT”},
    new {name=“Neo”,department=“IT”},
    new {name=“Loan”,department=“IT”}
    }
    };
    MiniExcel.SaveAsByTemplate(path, templatePath, value);

  2. 使用@group tag 和 @header` tag
    Before

before_with_header

After

after_with_header

  1. 使用 @group tag 没有 @header tag
    Before

before_without_header

After

after_without_header

  1. 没有 @group tag
    Before

without_group

After

without_group_after

  1. DataTable 当参数
    var managers = new DataTable();
    {
    managers.Columns.Add(“name”);
    managers.Columns.Add(“department”);
    managers.Rows.Add(“Jack”, “HR”);
    managers.Rows.Add(“Loan”, “IT”);
    }
    var value = new Dictionary<string, object>()
    {
    [“title”] = “FooCompany”,
    [“managers”] = managers,
    };
    MiniExcel.SaveAsByTemplate(path, templatePath, value);

  2. 其他

  3. 检查模版参数
    从 V1.24.0 版本开始,预设忽略模版不存在的参数Key,IgnoreTemplateParameterMissing 可以决定是否抛出错误

var config = new OpenXmlConfiguration()
{
IgnoreTemplateParameterMissing = false,
};
MiniExcel.SaveAsByTemplate(path, templatePath, value, config)

image

Excel 列属性 (Excel Column Attribute)

  1. 指定列名称、指定第几列、是否忽略该列
    Excel例子

image

代码

public class ExcelAttributeDemo
{
[ExcelColumnName(“Column1”)]
public string Test1 { get; set; }
[ExcelColumnName(“Column2”)]
public string Test2 { get; set; }
[ExcelIgnore]
public string Test3 { get; set; }
[ExcelColumnIndex(“I”)] // 系统会自动转换"I"为第8列
public string Test4 { get; set; }
public string Test5 { get; } //系统会忽略此列
public string Test6 { get; private set; } //set非公开,系统会忽略
[ExcelColumnIndex(3)] // 从0开始索引
public string Test7 { get; set; }
}

var rows = MiniExcel.Query(path).ToList();
Assert.Equal(“Column1”, rows[0].Test1);
Assert.Equal(“Column2”, rows[0].Test2);
Assert.Null(rows[0].Test3);
Assert.Equal(“Test7”, rows[0].Test4);
Assert.Null(rows[0].Test5);
Assert.Null(rows[0].Test6);
Assert.Equal(“Test4”, rows[0].Test7);

  1. 自定义Format格式 (ExcelFormatAttribute)
    從 V0.21.0 開始支持有 ToString(string content) 的類別 format

类别

public class Dto
{
public string Name { get; set; }

[ExcelFormat("MMMM dd, yyyy")]
public DateTime InDate { get; set; }

}

代码

var value = new Dto[] {
new Issue241Dto{ Name=“Jack”,InDate=new DateTime(2021,01,04)},
new Issue241Dto{ Name=“Henry”,InDate=new DateTime(2020,04,05)},
};
MiniExcel.SaveAs(path, value);

效果

image

Query 支持自定义格式转换

image

  1. 指定列宽(ExcelColumnWidthAttribute)
    public class Dto
    {
    [ExcelColumnWidth(20)]
    public int ID { get; set; }
    [ExcelColumnWidth(15.50)]
    public string Name { get; set; }
    }

  2. 多列名对应同一属性
    public class Dto
    {
    [ExcelColumnName(excelColumnName:“EmployeeNo”,aliases:new[] { “EmpNo”,“No” })]
    public string Empno { get; set; }
    public string Name { get; set; }
    }

  3. System.ComponentModel.DisplayNameAttribute = ExcelColumnName.excelColumnNameAttribute
    从 1.24.0 开始支持 System.ComponentModel.DisplayNameAttribute 等同于 ExcelColumnName.excelColumnNameAttribute 效果

public class TestIssueI4TXGTDto
{
public int ID { get; set; }
public string Name { get; set; }
[DisplayName(“Specification”)]
public string Spc { get; set; }
[DisplayName(“Unit Price”)]
public decimal Up { get; set; }
}

  1. ExcelColumnAttribute
    从 1.26.0 版本开始,可以简化多Attribute写法

     public class TestIssueI4ZYUUDto
     {
         [ExcelColumn(Name = "ID",Index =0)]
         public string MyProperty { get; set; }
         [ExcelColumn(Name = "CreateDate", Index = 1,Format ="yyyy-MM",Width =100)]
         public DateTime MyProperty2 { get; set; }
     }
    
  2. DynamicColumnAttribute 动态设定 Column
    从 1.26.0 版本开始,可以动态设定 Column 的属性

         var config = new OpenXmlConfiguration
         {
             DynamicColumns = new DynamicExcelColumn[] { 
                 new DynamicExcelColumn("id"){Ignore=true},
                 new DynamicExcelColumn("name"){Index=1,Width=10},
                 new DynamicExcelColumn("createdate"){Index=0,Format="yyyy-MM-dd",Width=15},
                 new DynamicExcelColumn("point"){Index=2,Name="Account Point"},
             }
         };
         var path = PathHelper.GetTempPath();
         var value = new[] { new { id = 1, name = "Jack", createdate = new DateTime(2022, 04, 12) ,point = 123.456} };
         MiniExcel.SaveAs(path, value, configuration: config);
    

image

新增、删除、修改
新增
v1.28.0 开始支持 CSV 插入新增,在最后一行新增N笔数据

// 原始数据
{
var value = new[] {
new { ID=1,Name =“Jack”,InDate=new DateTime(2021,01,03)},
new { ID=2,Name =“Henry”,InDate=new DateTime(2020,05,03)},
};
MiniExcel.SaveAs(path, value);
}
// 最后一行新增一行数据
{
var value = new { ID=3,Name = “Mike”, InDate = new DateTime(2021, 04, 23) };
MiniExcel.Insert(path, value);
}
// 最后一行新增N行数据
{
var value = new[] {
new { ID=4,Name =“Frank”,InDate=new DateTime(2021,06,07)},
new { ID=5,Name =“Gloria”,InDate=new DateTime(2022,05,03)},
};
MiniExcel.Insert(path, value);
}

image

删除(未完成)
修改(未完成)
Excel 类别自动判断
MiniExcel 预设会根据文件扩展名判断是 xlsx 还是 csv,但会有失准时候,请自行指定。
Stream 类别无法判断来源于哪种 excel 请自行指定
stream.SaveAs(excelType:ExcelType.CSV);
//or
stream.SaveAs(excelType:ExcelType.XLSX);
//or
stream.Query(excelType:ExcelType.CSV);
//or
stream.Query(excelType:ExcelType.XLSX);

CSV
概念
预设全以字串类型返回,预设不会转换为数字或者日期,除非有强型别定义泛型
自定分隔符
预设以 , 作为分隔符,自定义请修改 Seperator 属性

var config = new MiniExcelLibs.Csv.CsvConfiguration()
{
Seperator=‘;’
};
MiniExcel.SaveAs(path, values,configuration: config);

自定义换行符
预设以 \r\n 作为换行符,自定义请修改 NewLine 属性

var config = new MiniExcelLibs.Csv.CsvConfiguration()
{
NewLine=‘\n’
};
MiniExcel.SaveAs(path, values,configuration: config);

在 V1.30.1 版本开始支持动态更换换行符 (thanks @hyzx86)

var config = new CsvConfiguration()
{
SplitFn = (row) => Regex.Split(row, KaTeX parse error: Undefined control sequence: \t at position 3: "[\̲t̲,](?=(?:[^\"]|\…)“)
.Select(s => Regex.Replace(s.Replace(”“”“, “””), “^”|“$”, “”)).ToArray()
};
var rows = MiniExcel.Query(path, configuration: config).ToList();

自定义编码
预设编码为「从Byte顺序标记检测编码」(detectEncodingFromByteOrderMarks: true)
有自定义编码需求,请修改 StreamReaderFunc / StreamWriterFunc 属性
// Read
var config = new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamReaderFunc = (stream) => new StreamReader(stream,Encoding.GetEncoding(“gb2312”))
};
var rows = MiniExcel.Query(path, true,excelType:ExcelType.CSV,configuration: config);

// Write
var config = new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamWriterFunc = (stream) => new StreamWriter(stream, Encoding.GetEncoding(“gb2312”))
};
MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config);

DataReader

  1. GetReader
    从 1.23.0 版本开始能获取 DataReader

    using (var reader = MiniExcel.GetReader(path,true))
    {
    while (reader.Read())
    {
    for (int i = 0; i < reader.FieldCount; i++)
    {
    var value = reader.GetValue(i);
    }
    }
    }

异步 Async
从 v0.17.0 版本开始支持异步 (感谢isdaniel ( SHIH,BING-SIOU))
public static Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = “Sheet1”, ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null)
public static Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = “Sheet1”, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
public static Task<IEnumerable> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = “A1”, IConfiguration configuration = null)
public static Task<IEnumerable> QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = “A1”, IConfiguration configuration = null) where T : class, new()
public static Task<IEnumerable> QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = “A1”, IConfiguration configuration = null) where T : class, new()
public static Task<IEnumerable<IDictionary<string, object>>> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = “A1”, IConfiguration configuration = null)
public static Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value)
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
public static Task SaveAsByTemplateAsync(string path, string templatePath, object value)
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
public static Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = “A1”, IConfiguration configuration = null)

从 v1.25.0 开始支持 cancellationToken。
其他

  1. 映射枚举(enum)
    系统会自动映射(注意:大小写不敏感)

image

从V0.18.0版本开始支持Enum Description

public class Dto
{
public string Name { get; set; }
public Type UserType { get; set; }
}

public enum Type
{
[Description(“General User”)]
V1,
[Description(“General Administrator”)]
V2,
[Description(“Super Administrator”)]
V3
}

image

从 1.30.0 版本开始支持由 Description 转回 Enum 功能,感谢 @KaneLeung

  1. CSV 转 XLSX 或是 XLSX 转 CSV
    MiniExcel.ConvertXlsxToCsv(xlsxPath, csvPath);
    MiniExcel.ConvertXlsxToCsv(xlsxStream, csvStream);
    MiniExcel.ConvertXlsxToCsv(csvPath, xlsxPath);
    MiniExcel.ConvertXlsxToCsv(csvStream, xlsxStream);

  2. 自定义 CultureInfo
    从 1.22.0 版本开始,可以使用以下代码自定义文化信息,系统预设 CultureInfo.InvariantCulture。

var config = new CsvConfiguration()
{
Culture = new CultureInfo(“fr-FR”),
};
MiniExcel.SaveAs(path, value, configuration: config);

//or
MiniExcel.Query(path, configuration: config);

  1. 导出自定义 Buffer Size
    public abstract class Configuration : IConfiguration
    {
    public int BufferSize { get; set; } = 1024 * 512;
    }

  2. FastMode
    系统不会限制内存,达到更快的效率

var config = new OpenXmlConfiguration() { FastMode = true };
MiniExcel.SaveAs(path, reader,configuration:config);

例子

  1. SQLite & Dapper 读取大数据新增到数据库
    Note : 请不要呼叫 call ToList/ToArray 等方法,这会将所有数据读到内存内

using (var connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
using (var stream = File.OpenRead(path))
{
var rows = stream.Query();
foreach (var row in rows)
connection.Execute(“insert into T (A,B) values (@A,@B)”, new { row.A, row.B }, transaction: transaction);
transaction.Commit();
}
}

效能: image

  1. ASP.NET Core 3.1 下载/上传 Excel Xlsx API Demo Try it
    public class ApiController : Controller
    {
    public IActionResult Index()
    {
    return new ContentResult
    {
    ContentType = “text/html”,
    StatusCode = (int)HttpStatusCode.OK,
    Content = @"
    DownloadExcel

    DownloadExcelFromTemplatePath

    DownloadExcelFromTemplateBytes

Upload Excel


" }; }
public IActionResult DownloadExcel()
{
    var values = new[] {
        new { Column1 = "MiniExcel", Column2 = 1 },
        new { Column1 = "Github", Column2 = 2}
    };
    var memoryStream = new MemoryStream();
    memoryStream.SaveAs(values);
    memoryStream.Seek(0, SeekOrigin.Begin);
    return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    {
        FileDownloadName = "demo.xlsx"
    };
}

public IActionResult DownloadExcelFromTemplatePath()
{
    string templatePath = "TestTemplateComplex.xlsx";

    Dictionary<string, object> value = new Dictionary<string, object>()
    {
        ["title"] = "FooCompany",
        ["managers"] = new[] {
            new {name="Jack",department="HR"},
            new {name="Loan",department="IT"}
        },
        ["employees"] = new[] {
            new {name="Wade",department="HR"},
            new {name="Felix",department="HR"},
            new {name="Eric",department="IT"},
            new {name="Keaton",department="IT"}
        }
    };

    MemoryStream memoryStream = new MemoryStream();
    memoryStream.SaveAsByTemplate(templatePath, value);
    memoryStream.Seek(0, SeekOrigin.Begin);
    return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    {
        FileDownloadName = "demo.xlsx"
    };
}

private static Dictionary<string, Byte[]> TemplateBytesCache = new Dictionary<string, byte[]>();

static ApiController()
{
    string templatePath = "TestTemplateComplex.xlsx";
    byte[] bytes = System.IO.File.ReadAllBytes(templatePath);
    TemplateBytesCache.Add(templatePath, bytes);
}

public IActionResult DownloadExcelFromTemplateBytes()
{
    byte[] bytes = TemplateBytesCache["TestTemplateComplex.xlsx"];

    Dictionary<string, object> value = new Dictionary<string, object>()
    {
        ["title"] = "FooCompany",
        ["managers"] = new[] {
            new {name="Jack",department="HR"},
            new {name="Loan",department="IT"}
        },
        ["employees"] = new[] {
            new {name="Wade",department="HR"},
            new {name="Felix",department="HR"},
            new {name="Eric",department="IT"},
            new {name="Keaton",department="IT"}
        }
    };

    MemoryStream memoryStream = new MemoryStream();
    memoryStream.SaveAsByTemplate(bytes, value);
    memoryStream.Seek(0, SeekOrigin.Begin);
    return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    {
        FileDownloadName = "demo.xlsx"
    };
}

public IActionResult UploadExcel(IFormFile excel)
{
    var stream = new MemoryStream();
    excel.CopyTo(stream);

    foreach (var item in stream.Query(true))
    {
        // do your logic etc.
    }

    return Ok("File uploaded successfully");
}

}

  1. 分页查询
    void Main()
    {
    var rows = MiniExcel.Query(path);

    Console.WriteLine(“==== No.1 Page “);
    Console.WriteLine(Page(rows,pageSize:3,page:1));
    Console.WriteLine(”
    No.50 Page “);
    Console.WriteLine(Page(rows,pageSize:3,page:50));
    Console.WriteLine(”
    No.5000 Page ====”);
    Console.WriteLine(Page(rows,pageSize:3,page:5000));
    }

public static IEnumerable Page(IEnumerable en, int pageSize, int page)
{
return en.Skip(page * pageSize).Take(pageSize);
}

20210419

  1. WebForm不落地导出Excel
    var fileName = “Demo.xlsx”;
    var sheetName = “Sheet1”;
    HttpResponse response = HttpContext.Current.Response;
    response.Clear();
    response.ContentType = “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet”;
    response.AddHeader(“Content-Disposition”, $“attachment;filename=”{fileName}“”);
    var values = new[] {
    new { Column1 = “MiniExcel”, Column2 = 1 },
    new { Column1 = “Github”, Column2 = 2}
    };
    var memoryStream = new MemoryStream();
    memoryStream.SaveAs(values, sheetName: sheetName);
    memoryStream.Seek(0, SeekOrigin.Begin);
    memoryStream.CopyTo(Response.OutputStream);
    response.End();

  2. 动态 i18n 多国语言跟权限管理
    像例子一样,建立一个方法处理 i18n 跟权限管理,并搭配 yield return 返回 IEnumerable<Dictionary<string, object>>,即可达到动态、低内存处理效果

void Main()
{
var value = new Order[] {
new Order(){OrderNo = “SO01”,CustomerID=“C001”,ProductID=“P001”,Qty=100,Amt=500},
new Order(){OrderNo = “SO02”,CustomerID=“C002”,ProductID=“P002”,Qty=300,Amt=400},
};

Console.WriteLine("en-Us and Sales role");
{
	var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
	var lang = "en-US";
	var role = "Sales";
	MiniExcel.SaveAs(path, GetOrders(lang, role, value));
	MiniExcel.Query(path, true).Dump();
}

Console.WriteLine("zh-CN and PMC role");
{
	var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
	var lang = "zh-CN";
	var role = "PMC";
	MiniExcel.SaveAs(path, GetOrders(lang, role, value));
	MiniExcel.Query(path, true).Dump();
}

}

private IEnumerable<Dictionary<string, object>> GetOrders(string lang, string role, Order[] orders)
{
foreach (var order in orders)
{
var newOrder = new Dictionary<string, object>();

	if (lang == "zh-CN")
	{
		newOrder.Add("客户编号", order.CustomerID);
		newOrder.Add("订单编号", order.OrderNo);
		newOrder.Add("产品编号", order.ProductID);
		newOrder.Add("数量", order.Qty);
		if (role == "Sales")
			newOrder.Add("价格", order.Amt);
		yield return newOrder;
	}
	else if (lang == "en-US")
	{
		newOrder.Add("Customer ID", order.CustomerID);
		newOrder.Add("Order No", order.OrderNo);
		newOrder.Add("Product ID", order.ProductID);
		newOrder.Add("Quantity", order.Qty);
		if (role == "Sales")
			newOrder.Add("Amount", order.Amt);
		yield return newOrder;
	}
	else
	{
		throw new InvalidDataException($"lang {lang} wrong");
	}
}

}

public class Order
{
public string OrderNo { get; set; }
public string CustomerID { get; set; }
public decimal Qty { get; set; }
public string ProductID { get; set; }
public decimal Amt { get; set; }
}

image

FAQ 常见问题
Q: Excel 表头标题名称跟 class 属性名称不一致,如何对应?
A. 请使用 ExcelColumnName 作 mapping

image

Q. 多工作表(sheet)如何导出/查询数据?
A. 使用 GetSheetNames方法搭配 Query 的 sheetName 参数

var sheets = MiniExcel.GetSheetNames(path);
foreach (var sheet in sheets)
{
Console.WriteLine($"sheet name : {sheet} ");
var rows = MiniExcel.Query(path,useHeaderRow:true,sheetName:sheet);
Console.WriteLine(rows);
}

image

Q. 是否使用 Count 会载入全部数据到内存
不会,图片测试一百万行*十列数据,简单测试,内存最大使用 < 60MB,花费13.65秒

image

Q. Query如何使用整数索引取值?
Query 预设索引为字串Key : A,B,C…,想要改为数字索引,请建立以下方法自行转换

void Main()
{
var path = @“D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx”;
var rows = MiniExcel.Query(path,true);
foreach (var r in ConvertToIntIndexRows(rows))
{
Console.Write($“column 0 : {r[0]} ,column 1 : {r[1]}”);
Console.WriteLine();
}
}

private IEnumerable<Dictionary<int, object>> ConvertToIntIndexRows(IEnumerable rows)
{
ICollection keys = null;
var isFirst = true;
foreach (IDictionary<string,object> r in rows)
{
if(isFirst)
{
keys = r.Keys;
isFirst = false;
}

	var dic = new Dictionary<int, object>();
	var index = 0;
	foreach (var key in keys)
		dic[index++] = r[key];
	yield return dic;
}

}

Q. 导出时数组为空时生成没有标题空 Excel
因为 MiniExcel 使用类似 JSON.NET 动态从值获取类别机制简化 API 操作,没有数据就无法获取类别。可以查看 issue #133 了解。

image

强型别和 DataTable 会生成表头,但 Dicionary 依旧是空 Excel

Q. 如何人为空白行中止遍历?
常发生人为不小心在最后几行留下空白行情况,MiniExcel可以搭配 LINQ TakeWhile实现空白行中断遍历。

image

Q. 不想要空白行如何去除?
image

IEnumerable版本

public static IEnumerable QueryWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
{
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
foreach (IDictionary<string,object> row in rows)
{
if(row.Keys.Any(key=>row[key]!=null))
yield return row;
}
}

DataTable版本

public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
{
if (sheetName == null && excelType != ExcelType.CSV) /Issue #279/
sheetName = stream.GetSheetNames().First();

var dt = new DataTable(sheetName);
var first = true;
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
foreach (IDictionary<string, object> row in rows)
{
	if (first)
	{

		foreach (var key in row.Keys)
		{
			var column = new DataColumn(key, typeof(object)) { Caption = key };
			dt.Columns.Add(column);
		}

		dt.BeginLoadData();
		first = false;
	}

	var newRow = dt.NewRow();
	var isNull=true;
	foreach (var key in row.Keys)
	{
		var _v = row[key];
		if(_v!=null)
			isNull = false;
		newRow[key] = _v; 
	}
	
	if(!isNull)
		dt.Rows.Add(newRow);
}

dt.EndLoadData();
return dt;

}

Q. 保存如何取代MiniExcel.SaveAs(path, value),文件存在系统会报已存在错误?
请改以Stream自行管控Stream行为,如

using (var stream = File.Create("Demo.xlsx"))
	MiniExcel.SaveAs(stream,value);

从V1.25.0版本开始,支持 overwriteFile 參數,方便調整是否要覆蓋已存在文件

MiniExcel.SaveAs(path, value, overwriteFile: true);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2313957.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux(权限)

sudo 主要用来短暂的提权 权限 就是 >角色目标属性 这里面的角色就是---拥有者----所属组----other 所属组的目的&#xff1f; 更细化的管理 chmod 就是修改权限制 我们要是想要切换到体育的账号&#xff0c;我们可以去看一下有几个账号,我…

《OpenCV》—— dlib(换脸操作)

文章目录 dlib换脸介绍仿射变换在 dlib 换脸中的应用 换脸操作 dlib换脸介绍 dlib 换脸是基于 dlib 库实现的一种人脸替换技术&#xff0c;以下是关于它的详细介绍&#xff1a; 原理 人脸检测&#xff1a;dlib 库中包含先进的人脸检测器&#xff0c;如基于 HOG&#xff08;方向…

修改Flutter项目使用的JAVA版本

使用Android studio开发Flutter过程中&#xff0c;会默认使用Android studio自带的JDK。因为新版Android studio中的JDK版本过高&#xff0c;导致项目编译时总是无法完成&#xff0c;报【 unsupported class file major version 65】错误&#xff0c;如下&#xff1a; 解决这个…

虚拟dom的diff中的双端比较算法

‌双端比较算法是Vue中用于高效比较新旧VNode子节点的一种策略‌。该算法的核心思想是&#xff0c;通过从新旧VNode子节点的两端开始比较&#xff0c;逐步向中间靠拢&#xff0c;以找到最小的差异并据此更新DOM。以下是双端比较算法的大致流程&#xff1a; ‌初始化指针‌&…

VMware安装Windows server 2016

1、新建虚拟机&#xff0c;选择自定义模式 2、选择兼容性 4、命名虚拟机 5、固件类型 EFI 虚拟磁盘类型&#xff0c;不同电脑推荐的类型不同&#xff0c;用默认的就行 删除声卡和打印机 检查网络配置 选择本地的Windows server 2016的系统镜像&#xff0c;系统镜像可以去Window…

HippoRAG 2 原理精读

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 整体流程离线索引阶段在线检索和问答阶段 总结 整体流程 从上图可以看出&#xff0c;整个流程分为两个阶段 1、离线索引阶段 2、在线检索和问答阶段 离线索引阶段…

三:FFMPEG拉流读取模块的讲解

FFMPEG拉流读取模块在远程监控项目最核心的作用是读取UVC摄像头传输的H264码流&#xff0c;并对其码流进行帧的提取&#xff0c;提取完成之后则把数据传输到VDEC解码模块进行解码。而在我们这个项目中&#xff0c;UVC推流的功能由FFMPEG的命令完成。 FFMPEG拉流读取模块的API…

《苍穹外卖》SpringBoot后端开发项目核心知识点与常见问题整理(DAY1 to DAY3)

目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…

QT系列教程(20) Qt 项目视图便捷类

视频连接 https://www.bilibili.com/video/BV1XY41127t3/?vd_source8be9e83424c2ed2c9b2a3ed1d01385e9 Qt项目视图便捷类 Qt项目视图提供了一些便捷类&#xff0c;包括QListWidget, QTableWidget&#xff0c; QTreeWidget等。我们分别介绍这几个便捷类。 我们先创建一个Qt …

动态扩缩容引发的JVM堆内存震荡:从原理到实践的GC调优指南

目录 一、典型案例&#xff1a;系统发布后的GC雪崩事件 &#xff08;一&#xff09;故障现象 1. 刚刚启动时 GC 次数较多 2. 堆内存锯齿状波动 3. GC日志特征&#xff1a;Allocation Failure &#xff08;二&#xff09;问题定位 二、原理深度解析&#xff1a;JVM内存弹…

AI智能眼镜主控芯片:技术演进与产业生态的深度解析

一、AI智能眼镜的技术挑战与主控芯片核心诉求 AI智能眼镜作为XR&#xff08;扩展现实&#xff09;技术的代表产品&#xff0c;其核心矛盾在于性能、功耗与体积的三角平衡。主控芯片作为设备的“大脑”&#xff0c;需在有限空间内实现复杂计算、多模态交互与全天候续航&#xf…

微服务拆分-远程调用

我们在查询购物车列表的时候&#xff0c;它有一个需求&#xff0c;就是不仅仅要查出购物车当中的这些商品信息&#xff0c;同时还要去查到购物车当中这些商品的最新的价格和状态信息&#xff0c;跟购物车当中的快照进行一个对比&#xff0c;从而去提醒用户。 现在我们已经做了服…

[网络爬虫] 动态网页抓取 — Selenium 介绍 环境配置

&#x1f31f;想系统化学习爬虫技术&#xff1f;看看这个&#xff1a;[数据抓取] Python 网络爬虫 - 学习手册-CSDN博客 0x01&#xff1a;Selenium 工具介绍 Selenium 是一个开源的便携式自动化测试工具。它最初是为网站自动化测试而开发的&#xff0c;类似于我们玩游戏用的按…

【RAGFlow】windows本地pycharm运行

原因 由于官方只提供了docker部署&#xff0c;基于开源代码需要实现自己内部得逻辑&#xff0c;所以需要本地pycharm能访问&#xff0c;且docker运行依赖得其余组件&#xff0c;均需要使用开发服务器得配置。 修改过程 安装python 项目依赖于Python 版本&#xff1a;>3.1…

树莓派5首次开机保姆级教程(无显示器通过VNC连接树莓派桌面)

第一次开机详细步骤 步骤一&#xff1a;树莓派系统烧录1 搜索打开烧录软件“Raspberry Pi Imager”2 选择合适的设备、系统、SD卡3 烧录配置选项 步骤二&#xff1a;SSH远程树莓派1 树莓派插电2 网络连接&#xff08;有线或无线&#xff09;3 确定树莓派IP地址 步骤三&#xff…

html-表格标签

一、表格标签 1. 表格的主要作用 表格主要用于显示&#xff64;展示数据,因为它可以让数据显示的非常的规整,可读性非常好&#xff61;特别是后台展示数据 的时候,能够熟练运用表格就显得很重要&#xff61;一个清爽简约的表格能够把繁杂的数据表现得很有条理&#xff61; 总…

大模型安全新范式:DeepSeek一体机内容安全卫士发布

2月以来&#xff0c;DeepSeek一体机几乎成为了政企市场AI消费的最强热点。 通过一体机的方式能够缩短大模型部署周期&#xff0c;深度结合业务场景&#xff0c;降低中小企业对于大模型的使用门槛。据不完全统计&#xff0c;已约有超过60家企业基于DeepSeek推出一体机产品。 但…

数据分析绘制随时间顺序变化图加入线性趋势线——numpy库的polyfit计算一次多项式拟合

import pandas as pd import numpy as np import matplotlib.pyplot as plt# 导入数据 data pd.read_csv(rC:\Users\11712\notebooktrain1.csv)# 假设数据包含 date_time 和 speed 列 data[date_time] pd.to_datetime(data[date_time]) # 确保时间列是 datetime 类型 data.s…

密闭空间可燃气体监测终端:守护城市命脉,智驭燃气安全!

近年来&#xff0c;陕西省高度重视燃气安全&#xff0c;出台了一系列政策文件&#xff0c;旨在全面加强城镇燃气安全监管&#xff0c;防范化解重大安全风险。2023年&#xff0c;陕西省安委会印发《全省城镇燃气安全专项整治工作方案》&#xff0c;明确要求聚焦燃气经营、输送配…

阿里千问大模型(Qwen2.5-VL-7B-Instruct)部署

参考链接 知乎帖子 B站视频 huggingface 镜像网站&#xff08;不太全&#xff0c;比如 Qwen/Qwen2.5-VL-7B-Instruct就没有&#xff09; huggingface 5种下载方式汇总 通过huggingface-cli下载模型 不一样的部分是预训练权重的下载和demo 首先安装huggingface_hub pip insta…