/// Copyright(c) 2015-2016 pakkin. All Rights Reserved.
/// [改訂履歴]
/// 2015.11.08 作成
/// 2015.11.09 dynamic方式版を追加
/// 2015.11.19 1行1列しか存在しない場合を対応
/// 2015.11.30 空シート判定を修正
/// 2016.01.27 最終セルが結合セルのケースに対応
/// 2016.01.29 SortedListのReverse時の余計なインスタンス生成を削除
/// 2016.07.29 ClosedXMLやNPOIのケースも比較対象として追加
using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Linq;
using ClosedXML.Excel;
using NPOI.SS.UserModel;
namespace ConsoleApplication1
{
class Program
{
/// <summary>
/// Main
/// </summary>
/// <param name="args"></param>
public static void Main(string[] args)
{
Program.ExcelTest1(@"C:\temp\input.xlsx", "Sheet1", @"C:\temp\output1.xlsx");
Program.ExcelTest2(@"C:\temp\input.xlsx", "Sheet1", @"C:\temp\output2.xlsx");
Program.ExcelTest3(@"C:\temp\input.xlsx", "Sheet1", @"C:\temp\output3.xlsx");
Program.ExcelTest4(@"C:\temp\input.xlsx", "Sheet1", @"C:\temp\output4.xlsx");
Console.ReadKey(true);
}
/// <summary>
/// Dynamic方式
/// </summary>
/// <param name="readFile"></param>
/// <param name="sheetName"></param>
/// <param name="saveFile"></param>
private static void ExcelTest1(string readFile, string sheetName, string saveFile)
{
// 参照用配列
SortedList<string, dynamic> comList = new SortedList<string, dynamic>();
// EXCELへのアクセス行単位指定パラメータ(擬似的バルクフェッチ)
int bulkFetchRows = 600;
int bulkRowNo = -1;
Object[,] xlsData = null; // object:× Object:○
// コンソール出力用
int lastRow = 0;
DateTime start = DateTime.Now;
try
{
// 既存ファイルの読み込み
Type classType = Type.GetTypeFromProgID("Excel.Application");
comList["01xApp"] = Activator.CreateInstance(classType);
comList["01xApp"].DisplayAlerts = false;
comList["01xApp"].Visible = false;
comList["02boks"] = comList["01xApp"].Workbooks;
comList["03book"] = comList["02boks"].Open(readFile);
comList["04shts"] = comList["03book"].Worksheets;
comList["05shet"] = comList["04shts"].Item(sheetName);
comList["06cels"] = comList["05shet"].Cells;
comList["07spcc"] = comList["06cels"].SpecialCells(11);
string lastAddr = (string)comList["07spcc"].Address;
lastRow = (int)comList["07spcc"].Row;
int lastColN = (int)comList["07spcc"].Column;
lastAddr = lastAddr.Split(':')[lastAddr.Split(':').Length - 1]; // 2016.01.27 insert
string lastColC = lastAddr.Replace("$", "").Replace(lastRow.ToString(), "");
for (int fullRow = 0; fullRow <= lastRow; fullRow++)
{
// ----- 更新不要ならコメントアウト...ここから ------
if (fullRow > 0 && (fullRow == lastRow || bulkRowNo <= fullRow))
{
// エクセルに編集結果を反映
comList["08rnge"].Value = xlsData.GetLowerBound(0) == 1 ? xlsData : xlsData[1, 1];
// 保存
if (fullRow == lastRow) comList["03book"].SaveAs(saveFile);
}
// ----- 更新不要ならコメントアウト...ここまで ------
// 終了
if (fullRow == lastRow) break;
// エクセルから値を取得
if (bulkRowNo <= fullRow)
{
if (fullRow + bulkFetchRows > lastRow) bulkFetchRows = lastRow - fullRow;
bulkRowNo = fullRow + bulkFetchRows;
if (comList.ContainsKey("08rnge")) Marshal.FinalReleaseComObject(comList["08rnge"]);
if ("A" + (fullRow + 1) == lastColC + bulkRowNo)
{
comList["08rnge"] = comList["06cels"].Range("A" + (fullRow + 1));
Object tmp = comList["08rnge"].Value;
if (tmp == null && lastRow == 1) { lastRow = 0; break; } // 空白シートはファイル作成しない
xlsData = new Object[,] { { null, null }, { null, tmp } };
}
else
{
comList["08rnge"] = comList["06cels"].Range("A" + (fullRow + 1) + ":" + lastColC + bulkRowNo);
xlsData = (Object[,])comList["08rnge"].Value;
}
}
// エクセル行⇒擬似的バルクフェッチ配列行変換
int row = bulkFetchRows - bulkRowNo + fullRow + 1;
// 実際の編集処理はここでおこなう
for (int col = 1; col <= lastColN; col++)
{
// 値を編集
if (xlsData[row, col] == null)
{
xlsData[row, col] = "[null]";
}
else if (xlsData[row, col].GetType().Equals(typeof(System.Double)))
{
string add = string.Format("[double:{0,7}({1,3}):{2}]", fullRow + 1, row, col);
xlsData[row, col] = ((double)xlsData[row, col]).ToString("0") + add;
}
else if (xlsData[row, col].GetType().Equals(typeof(System.DateTime)))
{
string add = string.Format("[date:{0,7}({1,3}):{2}]", fullRow + 1, row, col);
xlsData[row, col] = ((DateTime)xlsData[row, col]).ToString("yyyy/MM/dd") + add;
}
else
{
string add = string.Format("[string:{0,7}({1,3}):{2}]", fullRow + 1, row, col);
xlsData[row, col] = (string)xlsData[row, col] + add;
}
}
}
}
catch (Exception ex)
{
// 例外
Console.WriteLine("Excel Automation Error!:{0}\r\n{1}", ex.Message, ex.StackTrace);
}
finally
{
// ファイルクローズ & 参照破棄(Reverse指定)
foreach (string key in comList.Keys.Reverse())
{
switch (key)
{
case "01xApp":
comList[key].Quit();
Marshal.FinalReleaseComObject(comList[key]);
break;
case "03book":
comList[key].Close();
break; // FinalReleaseComObject開放無し
default:
Marshal.FinalReleaseComObject(comList[key]);
break;
}
}
TimeSpan required = DateTime.Now - start;
Console.WriteLine("---- Dynamic方式 ----");
Console.WriteLine("Time required : {0} seconds.", required);
Console.WriteLine("Read/Write : {0} records.", lastRow);
}
}
/// <summary>
/// InvokeMember方式
/// </summary>
/// <param name="readFile"></param>
/// <param name="sheetName"></param>
/// <param name="saveFile"></param>
private static void ExcelTest2(string readFile, string sheetName, string saveFile)
{
// 参照用配列
SortedList<string, object> comList = new SortedList<string, object>();
// 遅延バインディングパラメータ
object[] pOpen = Enumerable.Repeat(Type.Missing, 15).ToArray(); pOpen[0] = readFile;
object[] pItem = new object[] { sheetName };
object[] pLastCell = new object[] { 11, Type.Missing };
// EXCELへのアクセス行単位指定パラメータ(擬似的バルクフェッチ)
int bulkFetchRows = 600;
int bulkRowNo = -1;
Object[,] xlsData = null; // object:× Object:○
// コンソール出力用
int lastRow = 0;
DateTime start = DateTime.Now;
try
{
// 既存ファイルの読み込み
Type classType = Type.GetTypeFromProgID("Excel.Application");
comList["01xApp"] = Activator.CreateInstance(classType);
comList["01xApp"].GetType().InvokeMember("DisplayAlerts", BindingFlags.SetProperty, null, comList["01xApp"], new object[] { false });
comList["01xApp"].GetType().InvokeMember("Visible", BindingFlags.SetProperty, null, comList["01xApp"], new object[] { false });
comList["02boks"] = comList["01xApp"].GetType().InvokeMember("Workbooks", BindingFlags.GetProperty, null, comList["01xApp"], null);
comList["03book"] = comList["02boks"].GetType().InvokeMember("Open", BindingFlags.InvokeMethod, null, comList["02boks"], pOpen);
comList["04shts"] = comList["03book"].GetType().InvokeMember("Worksheets", BindingFlags.GetProperty, null, comList["03book"], null);
comList["05shet"] = comList["04shts"].GetType().InvokeMember("Item", BindingFlags.GetProperty, null, comList["04shts"], pItem);
comList["06cels"] = comList["05shet"].GetType().InvokeMember("Cells", BindingFlags.GetProperty, null, comList["05shet"], null);
comList["07spcc"] = comList["06cels"].GetType().InvokeMember("SpecialCells", BindingFlags.GetProperty, null, comList["06cels"], pLastCell);
string lastAddr = (string)comList["07spcc"].GetType().InvokeMember("Address", BindingFlags.GetProperty, null, comList["07spcc"], null);
lastRow = (int)comList["07spcc"].GetType().InvokeMember("Row", BindingFlags.GetProperty, null, comList["07spcc"], null);
int lastColN = (int)comList["07spcc"].GetType().InvokeMember("Column", BindingFlags.GetProperty, null, comList["07spcc"], null);
lastAddr = lastAddr.Split(':')[lastAddr.Split(':').Length - 1]; // 2016.01.27 insert
string lastColC = lastAddr.Replace("$", "").Replace(lastRow.ToString(), "");
for (int fullRow = 0; fullRow <= lastRow; fullRow++)
{
// ----- 更新不要ならコメントアウト...ここから ------
if (fullRow > 0 && (fullRow == lastRow || bulkRowNo <= fullRow))
{
// エクセルに編集結果を反映
object[] pValue = new object[] { xlsData.GetLowerBound(0) == 1 ? xlsData : xlsData[1, 1] };
comList["08rnge"].GetType().InvokeMember("Value", BindingFlags.SetProperty, null, comList["08rnge"], pValue);
// 保存
if (fullRow == lastRow)
comList["03book"].GetType().InvokeMember("SaveAs", BindingFlags.InvokeMethod, null, comList["03book"], new object[] { saveFile });
}
// ----- 更新不要ならコメントアウト...ここまで ------
// 終了
if (fullRow == lastRow) break;
// エクセルから値を取得
if (bulkRowNo <= fullRow)
{
if (fullRow + bulkFetchRows > lastRow) bulkFetchRows = lastRow - fullRow;
bulkRowNo = fullRow + bulkFetchRows;
if (comList.ContainsKey("08rnge")) Marshal.FinalReleaseComObject(comList["08rnge"]);
if ("A" + (fullRow + 1) == lastColC + bulkRowNo)
{
object[] pRange = new object[] { "A" + (fullRow + 1) };
comList["08rnge"] = comList["06cels"].GetType().InvokeMember("Range", BindingFlags.GetProperty, null, comList["06cels"], pRange);
Object tmp = comList["08rnge"].GetType().InvokeMember("Value", BindingFlags.GetProperty, null, comList["08rnge"], null);
if (tmp == null && lastRow == 1) { lastRow = 0; break; } // 空白シートはファイル作成しない
xlsData = new Object[,] { { null, null }, { null, tmp } };
}
else
{
object[] pRange = new object[] { "A" + (fullRow + 1), lastColC + bulkRowNo };
comList["08rnge"] = comList["06cels"].GetType().InvokeMember("Range", BindingFlags.GetProperty, null, comList["06cels"], pRange);
xlsData = (Object[,])comList["08rnge"].GetType().InvokeMember("Value", BindingFlags.GetProperty, null, comList["08rnge"], null);
}
}
// エクセル行⇒擬似的バルクフェッチ配列行変換
int row = bulkFetchRows - bulkRowNo + fullRow + 1;
// 実際の編集処理はここでおこなう
for (int col = 1; col <= lastColN; col++)
{
// 値を編集
if (xlsData[row, col] == null)
{
xlsData[row, col] = "[null]";
}
else if (xlsData[row, col].GetType().Equals(typeof(System.Double)))
{
string add = string.Format("[double:{0,7}({1,3}):{2}]", fullRow + 1, row, col);
xlsData[row, col] = ((double)xlsData[row, col]).ToString("0") + add;
}
else if (xlsData[row, col].GetType().Equals(typeof(System.DateTime)))
{
string add = string.Format("[date:{0,7}({1,3}):{2}]", fullRow + 1, row, col);
xlsData[row, col] = ((DateTime)xlsData[row, col]).ToString("yyyy/MM/dd") + add;
}
else
{
string add = string.Format("[string:{0,7}({1,3}):{2}]", fullRow + 1, row, col);
xlsData[row, col] = (string)xlsData[row, col] + add;
}
}
}
}
catch (Exception ex)
{
// 例外
Console.WriteLine("Excel Automation Error!:{0}\r\n{1}", ex.Message, ex.StackTrace);
}
finally
{
// ファイルクローズ & 参照破棄(Reverse指定)
foreach (string key in comList.Keys.Reverse())
{
if (key == "03book")
comList["03book"].GetType().InvokeMember("Close", BindingFlags.InvokeMethod, null, comList["03book"], null);
if (key == "01xApp")
comList["01xApp"].GetType().InvokeMember("Quit", BindingFlags.InvokeMethod, null, comList["01xApp"], null);
Marshal.FinalReleaseComObject(comList[key]);
}
TimeSpan required = DateTime.Now - start;
Console.WriteLine("---- InvokeMember方式 ----");
Console.WriteLine("Time required : {0} seconds.", required);
Console.WriteLine("Read/Write : {0} records.", lastRow);
}
}
/// <summary>
/// 参考:ClosedXML方式
/// </summary>
/// <param name="readFile"></param>
/// <param name="sheetName"></param>
/// <param name="saveFile"></param>
private static void ExcelTest3(string readFile, string sheetName, string saveFile)
{
DateTime start = DateTime.Now;
try
{
File.Copy(readFile, saveFile, true);
using (XLWorkbook workbook = new XLWorkbook(saveFile))
using (IXLWorksheet worksheet = workbook.Worksheet(sheetName))
{
int lastRow = worksheet.LastRowUsed().RowNumber();
int lastCol = worksheet.LastColumnUsed().ColumnNumber();
for (int i = 1; i <= lastRow; i++)
{
for (int j = 1; j <= lastCol; j++)
{
IXLCell cell = worksheet.Cell(i, j);
if (cell.DataType == XLCellValues.Number)
{
string add = string.Format("[double:{0,7}:{1}]", i, j);
cell.Value = ((Double)cell.Value).ToString("0") + add;
}
else if (cell.DataType == XLCellValues.DateTime)
{
string add = string.Format("[date:{0,7}:{1}]", i, j);
cell.Value = ((DateTime)cell.Value).ToString("yyyy/MM/dd") + add;
}
else if (cell.DataType == XLCellValues.Text)
{
string txt = cell.Value.ToString();
string add = string.Format("[string:{0,7}:{1}]", i, j);
cell.Value = txt.Length == 0 ? "[null]" : txt + add;
}
}
}
workbook.Save();
TimeSpan required = DateTime.Now - start;
Console.WriteLine("---- ClosedXML方式 ----");
Console.WriteLine("Time required : {0} seconds.", required);
Console.WriteLine("Read/Write : {0} records.", lastRow);
}
}
catch (Exception ex)
{
TimeSpan required = DateTime.Now - start;
Console.WriteLine("---- ClosedXML方式 ----");
Console.WriteLine("Time required : {0} seconds.", required);
Console.WriteLine(ex.Message);
}
}
/// <summary>
/// 参考:NPOI方式
/// </summary>
/// <param name="readFile"></param>
/// <param name="sheetName"></param>
/// <param name="saveFile"></param>
private static void ExcelTest4(string readFile, string sheetName, string saveFile)
{
DateTime start = DateTime.Now;
IWorkbook workbook = null;
ISheet worksheet = null;
try
{
File.Copy(readFile, saveFile + "#", true);
workbook = WorkbookFactory.Create(saveFile + "#");
worksheet = workbook.GetSheet(sheetName);
{
int lastRow = worksheet.LastRowNum;
for (int i = 0; i <= lastRow; i++)
{
IRow row = worksheet.GetRow(i);
if (row == null) continue;
int col = 0;
List<int> newCellIndexes = new List<int>();
for (int j = 0; j < row.Cells.Count; j++)
{
ICell cell = row.Cells[j];
if (cell.CellType == CellType.Numeric && !DateUtil.IsCellDateFormatted(cell))
{
string add = string.Format("[double:{0,7}:{1}]", i + 1, j);
cell.SetCellValue(cell.NumericCellValue.ToString("0") + add);
}
else if (cell.CellType == CellType.Numeric)
{
string add = string.Format("[date:{0,7}:{1}]", i + 1, j);
cell.SetCellValue(cell.DateCellValue.ToString("yyyy/MM/dd") + add);
}
else if (cell.CellType == CellType.String)
{
string add = string.Format("[string:{0,7}:{1}]", i + 1, j);
cell.SetCellValue(cell.StringCellValue + add);
}
while (col < cell.ColumnIndex) newCellIndexes.Add(col++);
col++;
}
foreach (int j in newCellIndexes)
{
ICell cell = row.CreateCell(j, CellType.String);
cell.SetCellValue("[null]");
}
}
using (FileStream stream = new FileStream(saveFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
workbook.Write(stream);
}
TimeSpan required = DateTime.Now - start;
Console.WriteLine("---- NPOI方式 ----");
Console.WriteLine("Time required : {0} seconds.", required);
Console.WriteLine("Read/Write : {0} records.", lastRow + 1);
}
}
catch (Exception ex)
{
TimeSpan required = DateTime.Now - start;
Console.WriteLine("---- NPOI方式 ----");
Console.WriteLine("Time required : {0} seconds.", required);
Console.WriteLine(ex.Message);
}
finally
{
if (workbook != null) workbook.Close();
File.Delete(saveFile + "#");
}
}
}
}
Copyright(c) 2014-2022 pakkin. All Rights Reserved.