8

为了重现这个问题,我创建了一个控制台项目,下面是我Program.cs文件中的代码:

using System;
using System.IO;
using System.Threading;
using ClosedXML.Excel;

namespace TestSavingTwoBigFiles
{
    public class Program
    {
        private static string folderPath = @"C:\FOLDERPATH\";
        private static string fileName1 = folderPath + "FILENAME1.xlsm";
        private static string fileName2 = folderPath + "FILENAME2.xlsm";

        public static void StartThread(string ordinal, string fileName)
        {
            Console.WriteLine("Creating {0} file...", ordinal);
            var wb = new XLWorkbook(fileName, XLEventTracking.Disabled);
            try
            {
                using (wb)
                {
                    using (var ms = new MemoryStream())
                    {
                        Console.WriteLine("Saving {0} file...", ordinal);
                        wb.SaveAs(ms);
                    }
                }
                Console.WriteLine("{0} file saved successfully", ordinal);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                Console.ReadLine();
            }
        }

        public static void Main(string[] args)
        {
            var thread1 = new Thread(() => StartThread("first", fileName1));
            Console.WriteLine("Starting first thread");
            thread1.Start();

            var thread2 = new Thread(() => StartThread("second", fileName2));
            Console.WriteLine("Starting second thread");
            thread2.Start();
        }
    }
}

[感谢@EmilyLin 提供更简洁的版本]

当我用两个`.xlsm 文件运行上述程序时,一个是~2MB,另一个是~7MB,程序成功完成。但是,当我使用两个约 7MB 的文件运行它时,程序将卡在保存语句中,并且不会在不抛出异常的情况下继续运行。控制台将如下图所示保持不变。

控制台输出

我们使用的一种解决方法是锁定该SaveAs方法。有没有更好的办法?

谢谢!

4

1 回答 1

2

锁定该SaveAs方法可能是最好的方法。在 的源代码中XLWorkbook.cs,这两个SaveAs函数都使用FileStream和/或MemoryStream。这两个流都不是线程安全的,因此如果与多个线程同时运行,您的代码可能无法工作,因此您应该确保只有一个线程可以同时访问MemoryStream

这是一个例子:

using System;
using System.IO;
using System.Threading;
using ClosedXML.Excel;

namespace Whatever
{
    class Class1
    {
        private static readonly object lockObject = new object();

        public static void StartThread(string ordinal, string fileName)
        {
            Console.WriteLine(string.Format("creating {0} file...", ordinal));
            var wb = new XLWorkbook(fileName, XLEventTracking.Disabled);
            try
            {
                using (wb)
                using (var ms = new MemoryStream())
                {
                    lock (lockObject)
                    {
                        Console.WriteLine(string.Format("saving {0} file...", ordinal));
                        wb.SaveAs(ms);
                    }
                }
                Console.WriteLine(string.Format("{0} file saved successfully", ordinal));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        public static void Main(string[] args)
        {
            var thread1 = new Thread(() => StartThread("first", "a.xlsm"));
            thread1.Start();
            var thread2 = new Thread(() => StartThread("second", "b.xlsm"));
            thread2.Start();
        }
    }
}
于 2015-07-06T16:39:27.670 回答