//using AsbSaubReport; //using AutoMapper; using System; using System.IO; using System.Collections.Generic; using System.Linq; using ClosedXML.Excel; using ClosedXML.Excel.Drawings; namespace ConsoleApp1 { //var options = new DbContextOptionsBuilder() // .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True") // .Options; //var context = new AsbCloudDbContext(options); class Program { private static IXLWorksheet CopyImagesToAnotherSheet(IXLWorksheet sourceSheet, IXLWorksheet resultSheet) { foreach (var picture in sourceSheet.Pictures) { resultSheet.AddPicture(picture.ImageStream) .WithPlacement(XLPicturePlacement.Move) .WithSize(picture.Width, picture.Height) .MoveTo(resultSheet.Cell(picture.TopLeftCell.Address), picture.Left, picture.Top); } return resultSheet; } 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); } private static IXLRange GetCellsRange(IXLWorksheet sheet) { var firstTableCell = sheet.FirstCellUsed(); var lastTableCell = sheet.LastCellUsed(); var rngData = sheet.Range(firstTableCell.Address, lastTableCell.Address); return rngData; } // Изображения не переносятся при вызове метода sheet.CopyTo(). Падает с exception. // Для этого сначала все изображения переносятся на временный лист "PicsCopy", // затем удаляются из копируемого листа, копируемый лист копируется в лист-результат // и после этого из temp листа "PicsCopy" в лист-результат также копируются изображения. private static void CopySheetToFile(IXLWorksheet currentSheet, XLWorkbook resultExcelFile) { var picturesCopySheet = resultExcelFile.AddWorksheet("PicsCopy"); CopyImagesToAnotherSheet(currentSheet, picturesCopySheet); RemovePicturesFromSheet(currentSheet); var resultSheet = currentSheet.CopyTo(resultExcelFile, currentSheet.Name); CopyImagesToAnotherSheet(picturesCopySheet, resultSheet); picturesCopySheet.Delete(); } static void Main(/*string[] args*/) { var sourceExcelPaths = new List { //@"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" }; const string resultExcelPath = @"D:\excels\result.xlsx"; using var resultExcelFile = new XLWorkbook(); const int maxAllowedColumns = 256; foreach(var sourceExcelPath in sourceExcelPaths) { using var sourceExcelFile = new XLWorkbook(sourceExcelPath); Console.WriteLine($"Добавляется файл {Path.GetFileName(sourceExcelPath)}"); foreach (var sheet in sourceExcelFile.Worksheets) { // Если в файле очень много колонок и многие из них пустые - // предлагаем удалить их вручную или пытаемся копировать // ячейки попорядку (не красиво). Красиво не получится. if (sheet.Columns().Count() > maxAllowedColumns && sheet.Columns().Count() / sheet.ColumnsUsed().Count() > 3) { Console.WriteLine($"В файле {Path.GetFileName(sourceExcelPath)} " + $"{sheet.Columns().Count() - sheet.ColumnsUsed().Count()} пустых колонок " + $"без записей.\nЕсли продолжить выполнение, форматирование выходного " + $"листа может быть нарушено.\nДля сохранения структуры документа " + $"рекомендуется прервать выполнение и удалить неиспользуемые колонки.\n" + $"Продолжить выполнение? (y/n)"); var res = Console.ReadLine(); if (res != "y") return; var resultSheet = resultExcelFile.Worksheets.Add(sheet.Name); var rngData = GetCellsRange(sheet); rngData.CopyTo(resultSheet.Cell(1, 1)); var lastRowWithData = rngData.LastRowUsed().RangeAddress.LastAddress.RowNumber; for (int i = 1; i < lastRowWithData; i++) { resultSheet.Row(i).Height = sheet.Row(i).Height; resultSheet.Column(i).Width = sheet.Column(i).Width; } CopyImagesToAnotherSheet(sheet, resultSheet); GC.Collect(); } // Если колонок в файле немного, но среди них также есть пустые - // проще удалить ненужные колонки и скопировать лист красиво. else if (sheet.Columns().Count() < maxAllowedColumns && sheet.Columns().Count() / sheet.ColumnsUsed().Count() > 2) { var columnsToDelete = sheet.Columns() .Skip(sheet.ColumnsUsed().Count()); foreach (var d in columnsToDelete) d.Delete(); CopySheetToFile(sheet, resultExcelFile); GC.Collect(); } // Если по колонкам все хорошо, копируем лист красиво. else { CopySheetToFile(sheet, resultExcelFile); GC.Collect(); } } } resultExcelFile.SaveAs(resultExcelPath); Console.WriteLine("Done. Press any key to quit."); Console.ReadKey(); } } }