git_bsmd/ENI2/Excel/ExcelComparer.cs
Daniel Schick 6382b082ba Aktiver Bereich korrigiert
Die aktiven Zellen, d.h. die zu vergleichenden wurden nicht zuverlässig erkannt.
Ich habe daher eine andere Funktion verwendet, die ich auf Stackoverflow gefunden
habe. Ganz 100% sicher bin ich allerdings nicht, ob dieser Quatsch in jeder
Situation zufriedenstellend funktioniert.
2022-07-15 09:25:11 +02:00

202 lines
8.1 KiB
C#

// Copyright (c) 2022- schick Informatik
// Description: Compares excel files and highlights changes
//
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using Microsoft.Office.Interop.Excel;
namespace ENI2.Excel
{
/// <summary>
/// Diese Klasse beinhaltet den von Anmeldungen unabhängigen Vergleich von Excel Sheets. Damit
/// können dann Updates von "außen" einfacher abgearbeitet werden. Zellen und sheets werden bei
/// Aktualisierung bunt eingefärbt
/// </summary>
public static class ExcelComparer
{
private static int diffColor = ColorTranslator.ToOle(Color.FromArgb(150, 150, 255)); // blue
private static bool GetSheetRange(Worksheet sheet, out int lastUsedRow, out int lastUsedColumn)
{
try
{
sheet.Columns.ClearFormats();
sheet.Rows.ClearFormats();
Range usedRange = sheet.UsedRange;
lastUsedRow = usedRange.Rows.Count;
lastUsedColumn = usedRange.Columns.Count;
/*
Range last = sheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
Range range = sheet.get_Range("A1", last);
lastUsedRow = last.Row;
lastUsedColumn = last.Column;
*/
return true;
}
catch(Exception)
{
lastUsedColumn = 0;
lastUsedRow = 0;
return false;
}
}
private static string GetExcelColumnName(int columnNumber)
{
string columnName = "";
while (columnNumber > 0)
{
int modulo = (columnNumber - 1) % 26;
columnName = Convert.ToChar('A' + modulo) + columnName;
columnNumber = (columnNumber - modulo) / 26;
}
return columnName;
}
public static string Compare(string sourcePath, string targetPath, out string errorMessage)
{
string fileName = Path.GetTempPath() + Guid.NewGuid().ToString() + ".xlsx";
errorMessage = "";
int counter = 0;
try
{
File.Copy(targetPath, fileName);
ExcelReader source = new ExcelReader(sourcePath, true, false);
ExcelReader comparison = new ExcelReader(fileName, false, false);
/* erste Variante Vergleich über Namen der Zellen
// loop through named cells
foreach (string name in comparison.NameDict.Keys)
{
if (!source.NameDict.ContainsKey(name)) continue;
string sourceText = source.ReadText(name);
string targetText = comparison.ReadText(name);
if (sourceText == null)
{
if (targetText != null)
{
comparison.Colorize(name, diffColor);
counter++;
}
}
else if (targetText == null)
{
if (sourceText != null)
{
comparison.Colorize(name, diffColor);
counter++;
}
}
else if ((sourceText != null) && (targetText != null))
{
if (!sourceText.Equals(targetText))
{
// turn cell blue
comparison.Colorize(name, diffColor);
counter++;
}
}
}
*/
// Zweite Version durch alle Sheets werden Zellen der "used range" miteinander verglichen
foreach(Worksheet sourceSheet in source.Worksheets)
{
Worksheet targetSheet = null;
foreach(Worksheet sheet in comparison.Worksheets)
{
if (sourceSheet.Name.Equals(sheet.Name))
{
targetSheet = sheet;
break;
}
}
if (targetSheet == null) continue;
System.Diagnostics.Trace.WriteLine(string.Format("Processing sheet {0}", targetSheet.Name));
if(GetSheetRange(sourceSheet, out int sourceRows, out int sourceCols) && GetSheetRange(targetSheet, out int targetRows, out int targetCols))
{
// read source into 2 dim array
string rangeString = string.Format("A1:{0}{1}", GetExcelColumnName(Math.Max(sourceCols, targetCols)), Math.Max(sourceRows, targetRows));
object[,] sourceArray = sourceSheet.get_Range(rangeString).Value;
// read target into 2 dim array
object[,] targetArray = targetSheet.get_Range(rangeString).Value;
for (int rowidx = 1; rowidx <= Math.Max(sourceRows, targetRows); rowidx++)
{
for( int colidx = 1; colidx <= Math.Max(sourceCols, targetCols); colidx++)
{
string sourceText = null;
if(sourceArray[rowidx,colidx] != null) sourceText = sourceArray[rowidx,colidx].ToString();
string targetText = null;
if(targetArray[rowidx,colidx] != null) targetText = targetArray[rowidx, colidx].ToString();
if (sourceText == null)
{
if (targetText != null)
{
string targetRangeName = string.Format("{0}{1}", GetExcelColumnName(colidx), rowidx);
comparison.Colorize(targetSheet.Range[targetRangeName], diffColor);
counter++;
}
}
else if (targetText == null)
{
if (sourceText != null)
{
string targetRangeName = string.Format("{0}{1}", GetExcelColumnName(colidx), rowidx);
comparison.Colorize(targetSheet.Range[targetRangeName], diffColor);
counter++;
}
}
else if ((sourceText != null) && (targetText != null))
{
if (!sourceText.Equals(targetText))
{
string targetRangeName = string.Format("{0}{1}", GetExcelColumnName(colidx), rowidx);
// turn cell blue
comparison.Colorize(targetSheet.Range[targetRangeName], diffColor);
counter++;
}
}
}
}
}
else
{
errorMessage = "failed to get sheet ranges";
}
}
comparison.Save(fileName);
errorMessage = string.Format("{0} differences found", counter);
}
catch (Exception ex)
{
errorMessage = ex.Message;
}
return fileName;
}
}
}