【问题标题】:Read Excel Worksheets Asynchronously异步读取 Excel 工作表
【发布时间】:2019-04-08 21:29:06
【问题描述】:

我正在尝试异步读取给定工作簿的所有 Excel 工作表,但不知何故并没有发生。这个想法是将每个 Excel 工作表中的前 123 个单元格相加并在最后打印出来。该代码编译并运行没有错误,但它不会读取所有工作表,它只是跳过该部分,因为async

namespace SyncAndAsync
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Excel = Microsoft.Office.Interop.Excel;

    class Startup
    {
        static void Main()
        {
            string filePath = @"C:\Users\Desktop\Sample.xlsx";
            Excel.Application excel = new Excel.Application();
            excel.Visible = true;
            excel.EnableAnimations = false;
            Excel.Workbook wkb = Open(excel, filePath);

            var calculation = CalculateAllWorksheetsAsync(wkb);

            //foreach (var item in calculation)
            //{
            //    Console.WriteLine(item);
            //}

            excel.EnableAnimations = true;
            wkb.Close(true);
            excel.Quit();
        }

        static async Task<List<Information>> CalculateAllWorksheetsAsync(Excel.Workbook wkb)
        {

            List<Task<Information>> tasks = new List<Task<Information>>();

            foreach (Excel.Worksheet wks in wkb.Worksheets)
            {
                Task.Run(() => CalculateSingleWorksheetAsync(wks));
            }

            var results = await Task.WhenAll(tasks);
            return new List<Information>(results);
        }

        static async Task<Information> CalculateSingleWorksheetAsync(Excel.Worksheet wks)
        {
            Information output = new Information();
            int result = 0;
            await Task.Run(() =>
            {
                for (int i = 1; i <= 123; i++)
                {
                    result += (int)(wks.Cells[i, 1].Value);
                }
            });

            output.WorksheetName = wks.Name;
            output.WorksheetSum = result;
            Console.WriteLine($"{wks.Name} - {result}");
            return output;
        }

        static Excel.Workbook Open(Excel.Application excelInstance,
                                            string fileName, bool readOnly = false,
                                            bool editable = true, bool updateLinks = true)
        {
            Excel.Workbook book = excelInstance.Workbooks.Open(
                fileName, updateLinks, readOnly,
                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, editable, Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing);
            return book;
        }
    }
}

添加Information类使用Task,可能可以跳过:

namespace SyncAndAsync
{
    class Information
    {
        public string WorksheetName { get; set; } = "";
        public int WorksheetSum { get; set; } = 0;
    }
}

依赖关系:

  • 应添加引用Microsoft.Office.Interop.Excel
  • string filePath = @"C:\Users\Desktop\Sample.xlsx"; 更改为相关内容,并确保在 Excel 文件中每张工作表的第一列中有一些数字,以获得结果;

问题 - 如何使异步运行并显示所有工作表的总和?

【问题讨论】:

  • 你不需要等待 var 计算 = CalculateAllWorksheetsAsync(wkb); ?
  • @AJ_ - 一般而言 - 是的,但为此我必须使 Main() 异步,并且我正在避免这种情况(出于未知原因)。

标签: c# excel office-interop com-interop excel-interop


【解决方案1】:

有几个问题。首先,任务列表永远不会被填充,所以WhenAll 调用不会做任何事情。其次,主函数从不等待CalculateAllWorksheetsAsync 的结果。我对你的代码做了一些修改,见下文:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;

namespace ExcelTest {
    public class Information {
        public Information(string name, int sum) {
            Name = name;
            Sum = sum;
        }

        public string Name { get; set; }
        public int Sum { get; set; }
    }

    class Program {
        static void Main(){
            MainAsync().GetAwaiter().GetResult();
        }

        private static async Task MainAsync() {
            const string filePath = @"D:\file.xlsx";
            var excel = new Excel.Application {Visible = true, EnableAnimations = false};
            var wkb = Open(excel, filePath);

            var calculation = await CalculateAllWorksheetsAsync(wkb);

            foreach (var item in calculation) {
                Console.WriteLine($"{item.Name} - {item.Sum}");
            }

            excel.EnableAnimations = true;
            wkb.Close(true);
            excel.Quit();
            Console.Read();
        }

        private static async Task<List<Information>> CalculateAllWorksheetsAsync(Excel.Workbook wkb) {
            var tasks = wkb.Worksheets.Cast<Excel.Worksheet>().Select(CalculateSingleWorksheetAsync);
            var results = await Task.WhenAll(tasks);
            return results.ToList();
        }

        private static async Task<Information> CalculateSingleWorksheetAsync(Excel.Worksheet wks) {
            int result = await Task.Run(() =>
                Enumerable.Range(1, 123).Sum(index => (int) (wks.Cells[index, 1].Value2)));

            Console.WriteLine($"{wks.Name} - {result}");
            return new Information(wks.Name, result);
        }

        private static Excel.Workbook Open(Excel.Application excelInstance,
            string fileName, bool readOnly = false,
            bool editable = true, bool updateLinks = true) {
            return excelInstance.Workbooks.Open(
                fileName, updateLinks, readOnly,
                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, editable, Type.Missing, Type.Missing, Type.Missing,
                Type.Missing, Type.Missing);
        }
    }
}

示例输出:

【讨论】:

  • 看起来很有趣。你如何从这里开始 - private static async Task Main()?我收到错误 CS5001 程序不包含适合入口点的静态“主要”方法
  • 我猜问题出在我的 Visual Studio 中,它是 15.1 版,为了使用 private static async Task Main(),需要的版本是 15.3。
  • 是的,它需要较新的 C# 版本之一(我认为是 7.1)。如果您使用的版本不支持,您可以在这里获得一些想法:stackoverflow.com/questions/9208921/…
  • 是的,我需要一个新的 C# 版本。 :) 知道如何将这部分 int result = await Task.Run(() =&gt; Enumerable.Range(1, 123).Sum(index =&gt; (int)(wks.Cells[index, 1].Value2))); 升级为在求和之前检查空单元格是否不同于 null 吗?
猜你喜欢
  • 1970-01-01
  • 2013-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-27
相关资源
最近更新 更多