.NetCore 使用 NPOI 读取带有图片的excel数据

在.NetCore使用NPOI插件进行批量导入时,获取Excel中的所有的图片数据,存到集合中。


1.定义类PictureData
代码如下:

public class PictureData
{
    public byte[] Data { get; set; }
}

2.数据集引用

using NPOI.XSSF.UserModel;

using NPOI.SS.UserModel;

using NPOI.XSSF.UserModel.Extensions;

npoi插件可以通过nuget安装或自己下载引用。

3.定义获取excel图片数据的方法GetDTWithImg

    /// <summary>
    /// 获取excel中图片数据
    /// </summary>
    /// <param name="path">文件路径</param>
    /// <returns>list</returns>
 private List<PictureData> GetDTWithImg(string path)
    {
        using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            IWorkbook workbook = null;

            ISheet sheet = null;

            workbook = WorkbookFactory.Create(file);

            sheet = workbook.GetSheet("Sheet1");

            if (sheet == null)
            {
                sheet = workbook.GetSheetAt(0);
            }

            // 获取绘图对象
            XSSFDrawing drawing = (XSSFDrawing)sheet.CreateDrawingPatriarch();

            List<XSSFPicture> picturesInColumnA = new List<XSSFPicture>();

            List<XSSFShape> shapes = drawing.GetShapes();

            foreach (XSSFShape shape in shapes)
            {
                if (shape is XSSFPicture)
                {
                    XSSFPicture picture = (XSSFPicture)shape;

                    XSSFClientAnchor anchor = (XSSFClientAnchor)picture.GetPreferredSize();                  
                    picturesInColumnA.Add(picture);
                }
            }

            List<PictureData> pictureDataList = new List<PictureData>();

            //将图片数据放到集合中
            foreach (XSSFPicture picture in picturesInColumnA)
            {
                byte[] pictureData = picture.PictureData.Data;

                PictureData data = new PictureData
                {                   
                    Data = pictureData
                };

                pictureDataList.Add(data);
            }

            return pictureDataList;
        }

    }

通过该方法可以获取excel中的图片,将其转换成字节流存到集合中,方便后续对其进行操作。 

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。 

<think>好的,我现在需要帮助用户解决在.NET Core中实现每周定时任务,从数据库或文件读取两条记录的问题。首先,我需要回顾用户提供的引用内容,看看是否有相关的信息可以参考。 用户提到了几个引用,其中引用[2]是关于CacheUpdateService类使用BackgroundService和Timer来定时执行任务的例子,每5分钟触发一次。这可能对实现定时任务有帮助。引用[3]提到了Cron表达式,比如每天特定时间执行任务,用户需要每周执行,所以可能需要调整Cron表达式。引用[4]提到了Quartz.NET,这是一个在.NET中常用的任务调度框架,可能也是解决方案的一部分。 接下来,我需要确定用户的需求:每周执行一次,从数据库或文件中读取两条数据。可能的实现方式包括使用内置的BackgroundService配合Timer,或者使用第三方库如Quartz.NET或Hangfire。此外,还需要考虑如何读取数据,无论是从数据库还是文件,这部分可能需要不同的处理方式,但用户可能更关注定时任务的设置。 首先,BackgroundService是一个可行的方案,因为它是.NET Core内置的,适合简单的定时任务。例如,用户提到的引用[2]中的例子,每5分钟执行一次,可以修改为每周执行。但Timer的精度和可靠性可能不如专门的调度库,比如如果应用程序重启,可能需要重新计算下一次执行时间。 其次,Quartz.NET是一个强大的调度库,支持复杂的Cron表达式,适合需要精确调度的场景。用户需要每周执行一次,可以使用Cron表达式“0 0 * * 1”(每周一的零点),或者更精确的时间。引用[3]中的Cron表达式示例可以帮助构建正确的表达式。 另外,Hangfire也是一个选择,它提供了后台任务处理,支持持久化存储,适合需要可靠调度的应用。但用户可能需要额外的设置,比如数据库存储。 在数据读取部分,无论是数据库还是文件,都需要在任务触发时执行相应的读取操作。例如,使用Entity Framework Core查询数据库,或者使用System.IO读取文件内容,然后取前两条记录。 现在需要考虑不同方案的优缺点。BackgroundService简单,适合轻量级需求,但需要自己处理调度逻辑。Quartz.NET和Hangfire更强大,但需要引入额外的依赖。用户可能需要根据项目复杂性和维护需求来选择。 最后,需要提供具体的实现步骤,包括代码示例和配置说明。比如使用BackgroundService时如何设置每周触发,使用Quartz.NET时如何配置Job和Trigger,以及如何读取数据的方法。同时,要提醒用户注意时区问题、异常处理和数据读取的具体实现细节。</think>### 基于.NET Core的每周定时任务实现方案 #### 一、实现思路 通过后台服务+定时器实现周期性任务调度,结合数据库/文件读取逻辑。以下是三种常用方法: 1. **BackgroundService + Timer** .NET Core内置的后台服务框架,适合简单定时任务[^2] 2. **Quartz.NET** 专业任务调度框架,支持复杂Cron表达式[^4] 3. **Hangfire** 支持持久化任务存储,适用于分布式场景 --- #### 二、具体实现方式 ##### 方法1:BackgroundService实现 ```csharp public class WeeklyReaderService : BackgroundService { private Timer _timer; private readonly TimeSpan _interval = TimeSpan.FromDays(7); protected override Task ExecuteAsync(CancellationToken stoppingToken) { // 首次立即执行,后续每周执行 _timer = new Timer(DoWork, null, TimeSpan.Zero, _interval); return Task.CompletedTask; } private void DoWork(object state) { // 读取数据逻辑 var records = ReadFromDatabase(2); // 或 ReadFromFile(2) ProcessRecords(records); } private List<Record> ReadFromDatabase(int count) { using var context = new AppDbContext(); return context.Records.Take(count).ToList(); } public override void Dispose() { _timer?.Dispose(); base.Dispose(); } } ``` **注册服务:** ```csharp builder.Services.AddHostedService<WeeklyReaderService>(); ``` ##### 方法2:Quartz.NET实现 1. 安装NuGet包 ```bash dotnet add package Quartz ``` 2. 创建Job类 ```csharp public class WeeklyJob : IJob { public async Task Execute(IJobExecutionContext context) { var provider = context.Scheduler.Context["serviceProvider"] as IServiceProvider; using var scope = provider.CreateScope(); var dbContext = scope.ServiceProvider.GetService<AppDbContext>(); var records = dbContext.Records.Take(2).ToList(); await ProcessRecordsAsync(records); } } ``` 3. 配置调度器 ```csharp builder.Services.AddQuartz(q => { q.UseMicrosoftDependencyInjectionScopedJobFactory(); var jobKey = new JobKey("weeklyJob"); q.AddJob<WeeklyJob>(opts => opts.WithIdentity(jobKey)); q.AddTrigger(opts => opts .ForJob(jobKey) .WithIdentity("weeklyTrigger") .WithCronSchedule("0 0 12 ? * MON")); // 每周一中午12点执行 }); builder.Services.AddQuartzHostedService(); ``` ##### 方法3:文件读取示例 ```csharp private List<Record> ReadFromFile(string filePath, int count) { var json = File.ReadAllText(filePath); var records = JsonSerializer.Deserialize<List<Record>>(json); return records.Take(count).ToList(); } ``` --- #### 三、关键配置说明 1. **定时精度** Quartz的Cron表达式更精确,推荐格式:`0 0 12 ? * MON`(每周一12点)[^3] 2. **依赖注入** 数据库上下文需通过构造函数注入或从服务容器获取 3. **异常处理** 建议在定时任务中增加try-catch块,记录错误日志 4. **时区配置** Quartz调度器可指定时区: ```csharp .WithCronSchedule("0 0 12 ? * MON", x => x.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"))) ``` --- #### 四、方案对比 | 方案 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | BackgroundService | 无需第三方库,实现简单 | 重启后计时重置,精度较低 | 简单定时任务 | | Quartz.NET | 支持复杂调度策略,可靠性高 | 需要学习调度配置 | 生产级应用 | | Hangfire | 提供可视化界面,支持持久化 | 需要数据库支持 | 分布式系统 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

csdn_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值