为了重现这个问题,我创建了一个控制台项目,下面是我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
方法。还有更好的方法吗?
谢谢!
答案 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();
}
}
}