C# 我的Excel数据提取是否没有有效运行?
我正在编写一个控制台应用程序,它将从许多xls文件中提取数据,并将它们合并到一个大型csv中。 我已经在每个文件之间完成了所有Excel应用程序加载/GC,我担心这会导致应用程序花费的时间超过需要的时间 这是我的密码:C# 我的Excel数据提取是否没有有效运行?,c#,excel,performance,office-interop,C#,Excel,Performance,Office Interop,我正在编写一个控制台应用程序,它将从许多xls文件中提取数据,并将它们合并到一个大型csv中。 我已经在每个文件之间完成了所有Excel应用程序加载/GC,我担心这会导致应用程序花费的时间超过需要的时间 这是我的密码: namespace SubconDataExtractToCSV { class Program { static void Main(string[] args) { StreamWriter output
namespace SubconDataExtractToCSV
{
class Program
{
static void Main(string[] args)
{
StreamWriter outputCSV = new StreamWriter(@"C:\Users\mbelmer\Desktop\Helpful Files\Subcon Files\SubconEmailExtract\ExtractData\ExtractedData.csv", true);
DirectoryInfo folder = new DirectoryInfo(@"C:\Users\mbelmer\Desktop\Helpful Files\Subcon Files\SubconEmailExtract\");
FileInfo[] files = folder.GetFiles("*.xls");
foreach (var file in files)
{
ExtractData(file, outputCSV);
}
outputCSV.Close();
}
static void ExtractData(FileInfo filename, StreamWriter output)
{
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename.FullName);
Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
Excel.Range xlRange = xlWorksheet.UsedRange;
int rowCount = xlRange.Rows.Count;
int colCount = xlRange.Columns.Count;
string fileDate = filename.Name.Substring(0, 7);
if (filename.Name.Contains("WIP"))
{
//EXTRACT MMT
for(int i = 2; i <= rowCount; i++)
{
string dataLine = fileDate + ",";
for(int j = 1; j <= 10; j++)
{
if (xlRange.Cells[i, j].Value2 != null)
{
dataLine += xlRange.Cells[i, j].Value2 + ",";
}
else
{
dataLine += ",";
}
}
output.WriteLine(dataLine);
}
}
else
{
//EXTRACT AMKOR
for(int i = 2; i <= rowCount; i++)
{
string dataLine = fileDate + ",,,,,,,,,,,";
for(int j = 1; j <= colCount; j++)
{
if(xlRange.Cells[i,j].Value2 != null)
{
dataLine += xlRange.Cells[i, j].Value2 + ",";
}
else
{
dataLine += ",";
}
}
output.WriteLine(dataLine);
}
}
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.ReleaseComObject(xlRange);
Marshal.ReleaseComObject(xlWorksheet);
xlWorkbook.Close();
Marshal.ReleaseComObject(xlWorkbook);
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
}
}
dataextractocsv
{
班级计划
{
静态void Main(字符串[]参数)
{
StreamWriter outputCSV=新的StreamWriter(@“C:\Users\mbelmer\Desktop\Help Files\Subco Files\SubcommailExtract\ExtractData\ExtractedData.csv”,真);
DirectoryInfo文件夹=新的DirectoryInfo(@“C:\Users\mbelmer\Desktop\Help Files\Subco Files\SubcomailExtract\”;
FileInfo[]files=folder.GetFiles(“*.xls”);
foreach(文件中的var文件)
{
提取数据(文件、输出CSV);
}
outputCSV.Close();
}
静态void ExtractData(FileInfo文件名、StreamWriter输出)
{
Excel.Application xlApp=新的Excel.Application();
Excel.Workbook xlWorkbook=xlApp.Workbooks.Open(filename.FullName);
Excel._工作表xlWorksheet=xlWorkbook.Sheets[1];
Excel.Range xlRange=xlWorksheet.UsedRange;
int rowCount=xlRange.Rows.Count;
int colCount=xlRange.Columns.Count;
字符串fileDate=filename.Name.Substring(0,7);
if(filename.Name.Contains(“WIP”))
{
//提取蒙脱土
对于(inti=2;i,正如其他人所提到的,interop很奇怪,通常非常慢,尤其是对于大文件。但是,我知道有时您没有其他选择
我以前见过的一个可能的问题是使用“UsedRange”属性时。在循环中使用范围时速度非常慢。我在尝试删除大文件上“UsedRange”返回的“显然”空行和列时发现了这一点
当用户在Excel中设置单元格格式时…比如选择整行或整列,并为所选范围设置某种格式…然后“UsedRange”将选择此格式。您可能在“UsedRange”中看到此格式返回底部的一组空行或右侧的空列。这是因为即使单元格可能是空的…任何具有某种类型格式的单元格都将在UsedRange
属性中拾取
正是这些“明显的”空行和空列揭示了Excel互操作的缓慢之处。您可以查看我的答案以及其他用户提供的其他帮助
在我的测试中,我试着使用与上面答案相同的策略。基本上,它是这样的
如果在循环中使用范围
,就像代码对行所做的那样
dataLine += xlRange.Cells[i, j].Value2
和其他一些地方。这导致了一个很大的减速。由于某种原因,当你参考范围(xlRange
)时,它的速度是出了名的慢
幸运的是,有一个不那么困难的解决方案。在我以前的删除空行和空列的解决方案中,它是通过在任何循环中不使用“范围”来解决的
不要直接使用UsedRange
属性中的Range
,而是将使用的Range转换为两(2)维对象数组。然后循环对象数组,而不是Excel范围。这至少应该可以大大加快速度
例如,更改获取已使用范围的行
Excel.Range xlRange = xlWorksheet.UsedRange;
到
然后通过dataArray
而不是Excel范围进行循环。注意,由于dataArray
来自Excel.Range…它不会基于零(0),这意味着第一个索引将是一(1)。您将在我的示例中看到这一点
下面是一个使用您的代码的小测试,并将其与使用如上所述的对象数组的我的代码进行速度比较。在我的测试中,使用两个Excel文件,每个文件有5列和1000行,从秒表中可以看出存在显著差异。使用您的代码大约需要51000毫秒。使用我的代码,它可以耗时约2100毫秒
代码与您的类似,但是您可以看到,在循环中,我使用了对象数组而不是Excel范围
最后,我可能弄错了,但是,我会做更多的研究来调用垃圾收集器
GC.Collect();
GC.WaitForPendingFinalizers();
我认为你打电话给GC不会有任何收获
我希望这是有意义和有帮助的
我使用了winforms应用程序,button click方法将是代码中的主要方法
private void button1_Click(object sender, EventArgs e) {
StreamWriter outputCSV = new StreamWriter(@"D:\Test\Excel_Test\export.csv", true);
DirectoryInfo folder = new DirectoryInfo(@"D:\Test\Excel_Test\");
FileInfo[] files = folder.GetFiles("*.xlsx");
int count = 1;
Stopwatch sw = new Stopwatch();
sw.Start();
foreach (var file in files) {
//ExtractData(file, outputCSV);
ExtractData3(file, outputCSV);
count++;
}
MessageBox.Show("Done! It took: " + sw.ElapsedMilliseconds + " milliseconds");
outputCSV.Close();
}
private void ExtractData3(FileInfo filename, StreamWriter output) {
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename.FullName);
Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
Object[,] dataArray = (Object[,])xlWorksheet.UsedRange.Cells.Value2;
string fileDate = filename.Name.Substring(0, 7);
if (filename.Name.Contains("WIP")) {
//EXTRACT MMT
fileDate = fileDate + ",";
}
else {
//EXTRACT AMKOR
fileDate = fileDate + ",,,,,,,,,,,";
}
WriteData(dataArray, fileDate, output);
Marshal.ReleaseComObject(xlWorksheet);
xlWorkbook.Close();
Marshal.ReleaseComObject(xlWorkbook);
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
private void WriteData(Object[,] dataArray, string prefix, StreamWriter output) {
int rowCount = dataArray.GetLength(0);
int colCount = dataArray.GetLength(1);
StringBuilder sb = new StringBuilder();
sb.Append(prefix + ",");
for (int i = 1; i <= rowCount; i++) {
for (int j = 1; j <= colCount; j++) {
if (dataArray[i, j] != null) {
sb.Append(dataArray[i, j]);
if (j < colCount) {
sb.Append(",");
}
}
else {
sb.Append(",");
}
}
output.WriteLine(sb.ToString());
sb.Clear();
sb.Append(prefix + ",");
}
}
private void按钮1\u单击(对象发送者,事件参数e){
StreamWriter outputCSV=新的StreamWriter(@“D:\Test\Excel\u Test\export.csv”,true);
DirectoryInfo文件夹=新的DirectoryInfo(@“D:\Test\Excel\u Test\”);
FileInfo[]files=folder.GetFiles(“*.xlsx”);
整数计数=1;
秒表sw=新秒表();
sw.Start();
foreach(文件中的var文件){
//提取数据(文件、输出CSV);
提取数据3(文件,输出CSV);
计数++;
}
Show(“完成!耗时:”+sw.elapsedmillisons+“毫秒”);
outputCSV.Close();
}
私有void ExtractData3(FileInfo文件名,StreamWriter输出){
Excel.Application xlApp=新的Excel.Application();
Excel.Workbook xlWorkbook=xlApp.Workbooks.Open(filename.FullName);
Excel._工作表xlWorksheet=xlWorkbook.Sheets[1];
对象[,]数据数组=(对象[,])xlsheet.UsedRange.Cells.Value2;
字符串fileDate=filename.Name.Substring(0,7);
if(filename.Name.Contains(“WIP”)){
//提取蒙脱土
fileDate=fileDate+“,”;
}
否则{
//阿姆科提取物
fileDate=fileDate+“,,,,,,,,,,,,”;
}
WriteData(数据数组、文件日期、输出);
Marshal.ReleaseComObject(xlWorksheet);
xlWorkbook.Close();
Marshal.ReleaseComObject(xlWorkbook);
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
私有void WriteData(对象[,]数据数组,字符串前缀,StreamWriter输出)
private void button1_Click(object sender, EventArgs e) {
StreamWriter outputCSV = new StreamWriter(@"D:\Test\Excel_Test\export.csv", true);
DirectoryInfo folder = new DirectoryInfo(@"D:\Test\Excel_Test\");
FileInfo[] files = folder.GetFiles("*.xlsx");
int count = 1;
Stopwatch sw = new Stopwatch();
sw.Start();
foreach (var file in files) {
//ExtractData(file, outputCSV);
ExtractData3(file, outputCSV);
count++;
}
MessageBox.Show("Done! It took: " + sw.ElapsedMilliseconds + " milliseconds");
outputCSV.Close();
}
private void ExtractData3(FileInfo filename, StreamWriter output) {
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename.FullName);
Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
Object[,] dataArray = (Object[,])xlWorksheet.UsedRange.Cells.Value2;
string fileDate = filename.Name.Substring(0, 7);
if (filename.Name.Contains("WIP")) {
//EXTRACT MMT
fileDate = fileDate + ",";
}
else {
//EXTRACT AMKOR
fileDate = fileDate + ",,,,,,,,,,,";
}
WriteData(dataArray, fileDate, output);
Marshal.ReleaseComObject(xlWorksheet);
xlWorkbook.Close();
Marshal.ReleaseComObject(xlWorkbook);
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
}
private void WriteData(Object[,] dataArray, string prefix, StreamWriter output) {
int rowCount = dataArray.GetLength(0);
int colCount = dataArray.GetLength(1);
StringBuilder sb = new StringBuilder();
sb.Append(prefix + ",");
for (int i = 1; i <= rowCount; i++) {
for (int j = 1; j <= colCount; j++) {
if (dataArray[i, j] != null) {
sb.Append(dataArray[i, j]);
if (j < colCount) {
sb.Append(",");
}
}
else {
sb.Append(",");
}
}
output.WriteLine(sb.ToString());
sb.Clear();
sb.Append(prefix + ",");
}
}