diff --git a/ConsoleApp1/ConsoleApp1.csproj b/ConsoleApp1/ConsoleApp1.csproj index 392da02e..42fc49a5 100644 --- a/ConsoleApp1/ConsoleApp1.csproj +++ b/ConsoleApp1/ConsoleApp1.csproj @@ -7,7 +7,7 @@ - + diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index d395ee23..04877954 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -1,11 +1,10 @@ -using DocumentFormat.OpenXml; -using DocumentFormat.OpenXml.Packaging; -using DocumentFormat.OpenXml.Spreadsheet; -//using AsbSaubReport; +//using AsbSaubReport; //using AutoMapper; using System; +using System.IO; using System.Collections.Generic; using System.Linq; +using ClosedXML.Excel; namespace ConsoleApp1 { @@ -17,127 +16,87 @@ namespace ConsoleApp1 class Program { + private static void RemovePicturesFromSheet(IXLWorksheet sheet) + { + var picsNames = new List(); + + foreach (var p in sheet.Pictures) + picsNames.Add(p.Name); + + var filteredPics = picsNames.Distinct(); + + foreach (var n in filteredPics) + sheet.Pictures.Delete(n); + } static void Main(/*string[] args*/) { var sourceExcelPaths = new List { - @"D:\excels\excel1.xlsx", - @"D:\excels\excel2.xlsx" + //@"D:\excels\excel1.xlsx", + //@"D:\excels\excel2.xlsx" //@"D:\excels\e1.xlsx", //@"D:\excels\e2.xlsx", //@"D:\excels\e3.xlsx", - //@"D:\excels\e4.xlsx", - //@"D:\excels\e5.xlsx", - //@"D:\excels\e6.xlsx" + @"D:\excels\e4.XLSX", + @"D:\excels\e5.XLSX", + @"D:\excels\e6.XLSX" }; const string resultExcelPath = @"D:\excels\result.xlsx"; - // result file create and init - using (var resultExcelFile = SpreadsheetDocument.Create(resultExcelPath, - SpreadsheetDocumentType.Workbook, true)) + using var resultExcelFile = new XLWorkbook(); + + const int maxAllowedColumns = 256; + + foreach(var sourceExcelPath in sourceExcelPaths) { - var workbookPart = resultExcelFile.AddWorkbookPart(); - workbookPart.Workbook = new Workbook(); + using var sourceExcelFile = new XLWorkbook(sourceExcelPath); - workbookPart.Workbook.AppendChild(new Sheets()); - - resultExcelFile.WorkbookPart.AddNewPart(); - resultExcelFile.WorkbookPart.SharedStringTablePart.SharedStringTable = new SharedStringTable(); - resultExcelFile.WorkbookPart.AddNewPart(); - - workbookPart.Workbook.Save(); - } - - foreach (var sourceExcelPath in sourceExcelPaths) - { - using var sourceExcelFile = SpreadsheetDocument.Open(sourceExcelPath, false); - - using var resultExcelFile = SpreadsheetDocument.Open(resultExcelPath, true); - - foreach (var sheet in sourceExcelFile.WorkbookPart.Workbook.Descendants()) + foreach (var sheet in sourceExcelFile.Worksheets) { - // Чтобы писать на новый лист, нужен новый WorkSheetPart, WorkSheet, SheetData и Sheet. - // https://stackoverflow.com/questions/9120544/openxml-multiple-sheets + //var columnsToDelete = sheet.Columns().Skip(sheet.ColumnsUsed().Count()); - var resultExcelWorkSheetPart = resultExcelFile.WorkbookPart.AddNewPart(); - resultExcelWorkSheetPart.Worksheet = new Worksheet(); + //foreach (var d in columnsToDelete) + // d.Delete(); - var resultExcelSheetData = resultExcelWorkSheetPart. - Worksheet.AppendChild(new SheetData()); - - var newSheet = new Sheet() + if (sheet.Columns().Count() > maxAllowedColumns && + sheet.Columns().Count() / sheet.ColumnsUsed().Count() > 5) { - Id = resultExcelFile.WorkbookPart.GetIdOfPart(resultExcelWorkSheetPart), - SheetId = sheet.SheetId.Value, - Name = sheet.Name - }; + Console.WriteLine($"В файле {Path.GetFileName(sourceExcelPath)} " + + $"{sheet.Columns().Count() - sheet.ColumnsUsed().Count()} пустых колонок " + + $"без записей. \n Если продолжить выполнение, форматирование выходного" + + $"листа может быть нарушено. \n Для сохранения структуры документа " + + $"рекомендуется прервать выполнение и удалить неиспользуемые колонки. \n" + + $" Продолжить выполнение? (y/n)"); - resultExcelFile.WorkbookPart.Workbook.Sheets.Append(newSheet); + var res = Console.ReadLine(); - var sourceWorkSheetPart = sourceExcelFile.WorkbookPart. - GetPartById(sheet.Id) as WorksheetPart; + if (res != "y") + return; - // Не самая лучшая выборка рядов текущей страницы исходного файла. - // Наверняка для этого есть метод. - var sourceFileCurrentListRows = sourceWorkSheetPart.Worksheet.ChildElements - .FirstOrDefault(w => w.LocalName == "sheetData").ChildElements; + var firstTableCell = sheet.FirstCellUsed(); + var lastTableCell = sheet.LastCellUsed(); + var rngData = sheet.Range(firstTableCell.Address, lastTableCell.Address); - // Числовые ячейки хранятся как есть и переносятся без проблем, а вот значения строковых ячеек хранятся - // в отдельной таблице. При этом в самой строковой ячейке хранится индекс этой строки в таблице - // (чтоб не хранить кучу одинаковых строк в документе. Что-то вроде интернирования строк). - // Тут как раз переносится клон этой таблицы из исходного файла в результирующий. - // Разные всяческие Part'ы можно найти тут: - // https://docs.microsoft.com/ru-ru/dotnet/api/documentformat.openxml.packaging.spreadsheetdocument.workbookpart?view=openxml-2.8.1 + RemovePicturesFromSheet(sheet); - var sourceExcelStringTable = sourceExcelFile.WorkbookPart.GetPartsOfType() - .FirstOrDefault().SharedStringTable; + var wsCopy = resultExcelFile.Worksheets.Add(sheet.Name); + wsCopy.Cell(1, 1).Value = rngData; - //resultExcelFile.WorkbookPart.SharedStringTablePart.SharedStringTable.Load(sourceExcelFile.WorkbookPart.SharedStringTablePart); - //sourceExcelStringTable.CloneNode(true) as SharedStringTable; - - // Аналогично переносим таблицу стилей ячеек (жирный шрифт и прочее). - // Иначе ячейки переносятся абсолютно обычными, без всякой стилизации. - - var stylesSheet = sourceExcelFile.WorkbookPart.GetPartsOfType() - .FirstOrDefault().Stylesheet; - resultExcelFile.WorkbookPart.WorkbookStylesPart.Stylesheet = - stylesSheet.CloneNode(true) as Stylesheet; - - // Клонируем ряды в новый файл (без клонирования они не вытаскиваются из общего дерева) - - foreach (var row in sourceFileCurrentListRows) + GC.Collect(); + } + else { - var newCells = new List(); + RemovePicturesFromSheet(sheet); - foreach(var c in row.ChildElements) - { - var cell = (Cell)c; - if (cell.DataType is not null && cell.DataType.Value == CellValues.SharedString) - { - var cellValue = sourceExcelStringTable.ElementAt(int.Parse(cell.InnerText)).InnerText; - - newCells.Add(new Cell { - CellReference = cell.CellReference, - DataType = CellValues.String, - CellValue = new CellValue(cellValue) - }); - } - else - newCells.Add(cell.CloneNode(true) as Cell); - } - - var newRow = row.CloneNode(true); - - newRow.RemoveAllChildren(); - newRow.Append(newCells); - resultExcelSheetData.AppendChild(newRow); + sheet.CopyTo(resultExcelFile, sheet.Name); + GC.Collect(); } } } - + resultExcelFile.SaveAs(resultExcelPath); Console.WriteLine("Done. Press any key to quit."); Console.ReadKey();