当同时保存两个.xlsm文件(每个大约7MB)时,ClosedXML .SaveAs(MemoryStream ms)不会进展

时间:2015-07-06 15:35:37

标签: c# closedxml

为了重现这个问题,我创建了一个控制台项目,下面是我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文件运行它时,程序将停留在保存语句中,并且不会在不抛出异常的情况下继续运行。控制台将保留,如下图所示,并且不会更改。

Console Output

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

谢谢!

1 个答案:

答案 0 :(得分:1)

锁定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();
        }
    }
}