异步读取Excel工作表

3

我试图异步读取给定工作簿的所有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 类来使用任务,可能可以跳过:

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文件的每个工作表中第一列都有一些数字,以获取结果;

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


1
你不需要等待变量 calculation = CalculateAllWorksheetsAsync(wkb) 吗? - AJ_
@AJ_ - 一般来说 - 是的,但是为了这个我不得不把 Main() 改成异步的,而我一直在避免这样做(原因未知)。 - Vityata
1个回答

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);
        }
    }
}

样例输出:

enter image description here


听起来很有趣。你从这里怎么开始——private static async Task Main()?我遇到了一个错误,错误 CS5001:程序不包含静态的适用于入口点的'Main'方法 - Vityata
我猜问题在我的Visual Studio中,它是15.1版本,而要使用private static async Task Main(),需要的版本是15.3。 - Vityata
1
是的,它需要较新的C#版本(我认为是7.1)。如果您使用的版本不支持该功能,则可以在此处获取一些想法:https://dev59.com/EGox5IYBdhLWcg3wcT3r - Evan Trimboli
是的,我需要一个新的C#版本。 :) 有什么想法可以升级这部分 int result = await Task.Run(() => Enumerable.Range(1, 123).Sum(index => (int)(wks.Cells[index, 1].Value2))); ,以便在求和之前检查空单元格是否与 null 不同? - Vityata

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接