From 1d54c1679e82943bd3fac55e22f825cdcb0bf5f6 Mon Sep 17 00:00:00 2001 From: KharchenkoVV Date: Mon, 20 Sep 2021 12:10:15 +0500 Subject: [PATCH 1/4] Fixed columns and rows sizes in result file --- ConsoleApp1/Program.cs | 70 +++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index 03daec69..aea971ea 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -5,6 +5,7 @@ using System.IO; using System.Collections.Generic; using System.Linq; using ClosedXML.Excel; +using ClosedXML.Excel.Drawings; namespace ConsoleApp1 { @@ -16,17 +17,16 @@ namespace ConsoleApp1 class Program { - private static void RemovePicturesFromSheet(IXLWorksheet sheet) + private static void CopyImages(IXLWorksheet sourceSheet, IXLWorksheet resultSheet) { - 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); + foreach (var picture in sourceSheet.Pictures) + { + var newImage = resultSheet.AddPicture(picture.ImageStream) + .WithPlacement(XLPicturePlacement.FreeFloating) + .WithSize(picture.Width, picture.Height) + .MoveTo(resultSheet.Cell(picture.TopLeftCell.Address), + picture.Left, picture.Top); + } } private static IXLRange GetCellsRange(IXLWorksheet sheet) @@ -45,10 +45,10 @@ namespace ConsoleApp1 //@"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\e2.xlsx", + //@"D:\excels\e3.xlsx", + //@"D:\excels\e4.XLSX", + //@"D:\excels\e5.XLSX", @"D:\excels\e6.XLSX" }; @@ -62,32 +62,43 @@ namespace ConsoleApp1 { 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() > 5) + sheet.Columns().Count() / sheet.ColumnsUsed().Count() > 3) { Console.WriteLine($"В файле {Path.GetFileName(sourceExcelPath)} " + $"{sheet.Columns().Count() - sheet.ColumnsUsed().Count()} пустых колонок " + - $"без записей. \n Если продолжить выполнение, форматирование выходного" + - $"листа может быть нарушено. \n Для сохранения структуры документа " + - $"рекомендуется прервать выполнение и удалить неиспользуемые колонки. \n" + - $" Продолжить выполнение? (y/n)"); + $"без записей.\nЕсли продолжить выполнение, форматирование выходного " + + $"листа может быть нарушено.\nДля сохранения структуры документа " + + $"рекомендуется прервать выполнение и удалить неиспользуемые колонки.\n" + + $"Продолжить выполнение? (y/n)"); var res = Console.ReadLine(); if (res != "y") return; + var resultSheet = resultExcelFile.Worksheets.Add(sheet.Name); + //resultSheet.Cell(1, 1).Value = rngData; + var rngData = GetCellsRange(sheet); - RemovePicturesFromSheet(sheet); + rngData.CopyTo(resultSheet.Cell(1, 1)); - var wsCopy = resultExcelFile.Worksheets.Add(sheet.Name); - wsCopy.Cell(1, 1).Value = rngData; + 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; + } + + CopyImages(sheet, resultSheet); GC.Collect(); } @@ -96,22 +107,25 @@ namespace ConsoleApp1 else if (sheet.Columns().Count() < maxAllowedColumns && sheet.Columns().Count() / sheet.ColumnsUsed().Count() > 2) { - RemovePicturesFromSheet(sheet); - - var columnsToDelete = sheet.Columns().Skip(sheet.ColumnsUsed().Count()); + var columnsToDelete = sheet.Columns() + .Skip(sheet.ColumnsUsed().Count()); foreach (var d in columnsToDelete) d.Delete(); - sheet.CopyTo(resultExcelFile, sheet.Name); + var resultSheet = sheet.CopyTo(resultExcelFile, sheet.Name); + + CopyImages(sheet, resultSheet); + GC.Collect(); } // Если по колонкам все хорошо, копируем лист красиво. else { - RemovePicturesFromSheet(sheet); + var resultSheet = sheet.CopyTo(resultExcelFile, sheet.Name); + + CopyImages(sheet, resultSheet); - sheet.CopyTo(resultExcelFile, sheet.Name); GC.Collect(); } } From ddcb90870fc8eb2904cc37e5abb528432d04830e Mon Sep 17 00:00:00 2001 From: KharchenkoVV Date: Mon, 20 Sep 2021 15:12:02 +0500 Subject: [PATCH 2/4] Added images copying --- ConsoleApp1/Program.cs | 67 ++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index aea971ea..ef014e22 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -17,16 +17,31 @@ namespace ConsoleApp1 class Program { - private static void CopyImages(IXLWorksheet sourceSheet, IXLWorksheet resultSheet) + private static IXLWorksheet CopyImagesToAnotherSheet(IXLWorksheet sourceSheet, IXLWorksheet resultSheet) { foreach (var picture in sourceSheet.Pictures) { - var newImage = resultSheet.AddPicture(picture.ImageStream) - .WithPlacement(XLPicturePlacement.FreeFloating) - .WithSize(picture.Width, picture.Height) - .MoveTo(resultSheet.Cell(picture.TopLeftCell.Address), - picture.Left, picture.Top); + 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) @@ -38,17 +53,36 @@ namespace ConsoleApp1 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\e1.xlsx", + @"D:\excels\e2.xlsx", + @"D:\excels\e3.xlsx", + @"D:\excels\e4.XLSX", + @"D:\excels\e5.XLSX", @"D:\excels\e6.XLSX" }; @@ -84,7 +118,6 @@ namespace ConsoleApp1 return; var resultSheet = resultExcelFile.Worksheets.Add(sheet.Name); - //resultSheet.Cell(1, 1).Value = rngData; var rngData = GetCellsRange(sheet); @@ -98,7 +131,7 @@ namespace ConsoleApp1 resultSheet.Column(i).Width = sheet.Column(i).Width; } - CopyImages(sheet, resultSheet); + CopyImagesToAnotherSheet(sheet, resultSheet); GC.Collect(); } @@ -113,18 +146,14 @@ namespace ConsoleApp1 foreach (var d in columnsToDelete) d.Delete(); - var resultSheet = sheet.CopyTo(resultExcelFile, sheet.Name); - - CopyImages(sheet, resultSheet); + CopySheetToFile(sheet, resultExcelFile); GC.Collect(); } // Если по колонкам все хорошо, копируем лист красиво. else { - var resultSheet = sheet.CopyTo(resultExcelFile, sheet.Name); - - CopyImages(sheet, resultSheet); + CopySheetToFile(sheet, resultExcelFile); GC.Collect(); } From 5d21d841a26c3ce84299f1dae54171562bdec352 Mon Sep 17 00:00:00 2001 From: KharchenkoVV Date: Tue, 21 Sep 2021 12:10:15 +0500 Subject: [PATCH 3/4] Removed unnecessary code from excel files union --- ConsoleApp1/Program.cs | 64 +++++++++--------------------------------- 1 file changed, 13 insertions(+), 51 deletions(-) diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index ef014e22..5f95a59a 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -17,7 +17,8 @@ namespace ConsoleApp1 class Program { - private static IXLWorksheet CopyImagesToAnotherSheet(IXLWorksheet sourceSheet, IXLWorksheet resultSheet) + private static IXLWorksheet CopyImagesToAnotherSheet(IXLWorksheet sourceSheet, + IXLWorksheet resultSheet) { foreach (var picture in sourceSheet.Pictures) { @@ -33,12 +34,7 @@ namespace ConsoleApp1 private static void RemovePicturesFromSheet(IXLWorksheet sheet) { - var picsNames = new List(); - - foreach (var p in sheet.Pictures) - picsNames.Add(p.Name); - - var filteredPics = picsNames.Distinct(); + var filteredPics = sheet.Pictures.Select(p => p.Name).Distinct().ToList(); foreach (var n in filteredPics) sheet.Pictures.Delete(n); @@ -57,9 +53,11 @@ namespace ConsoleApp1 // Для этого сначала все изображения переносятся на временный лист "PicsCopy", // затем удаляются из копируемого листа, копируемый лист копируется в лист-результат // и после этого из temp листа "PicsCopy" в лист-результат также копируются изображения. + // Temp лист удаляется. private static void CopySheetToFile(IXLWorksheet currentSheet, XLWorkbook resultExcelFile) { var picturesCopySheet = resultExcelFile.AddWorksheet("PicsCopy"); + var copy = currentSheet.Pictures.Select(p => new { buff = p.ImageStream, }); CopyImagesToAnotherSheet(currentSheet, picturesCopySheet); @@ -78,7 +76,7 @@ namespace ConsoleApp1 { //@"D:\excels\excel1.xlsx", //@"D:\excels\excel2.xlsx" - @"D:\excels\e1.xlsx", + //@"D:\excels\e1.xlsx", @"D:\excels\e2.xlsx", @"D:\excels\e3.xlsx", @"D:\excels\e4.XLSX", @@ -88,42 +86,28 @@ namespace ConsoleApp1 const string resultExcelPath = @"D:\excels\result.xlsx"; - using var resultExcelFile = new XLWorkbook(); + using var resultExcelFile = new XLWorkbook(XLEventTracking.Disabled); const int maxAllowedColumns = 256; foreach(var sourceExcelPath in sourceExcelPaths) { - using var sourceExcelFile = new XLWorkbook(sourceExcelPath); + using var sourceExcelFile = new XLWorkbook(sourceExcelPath, XLEventTracking.Disabled); Console.WriteLine($"Добавляется файл {Path.GetFileName(sourceExcelPath)}"); + foreach (var sheet in sourceExcelFile.Worksheets) { - // Если в файле очень много колонок и многие из них пустые - - // предлагаем удалить их вручную или пытаемся копировать - // ячейки попорядку (не красиво). Красиво не получится. - if (sheet.Columns().Count() > maxAllowedColumns && - sheet.Columns().Count() / sheet.ColumnsUsed().Count() > 3) + if (sheet.Columns().Count() > maxAllowedColumns) { - 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; + var lastRowWithData = rngData.LastRowUsed().RangeAddress + .LastAddress.RowNumber; for (int i = 1; i < lastRowWithData; i++) { @@ -132,35 +116,13 @@ namespace ConsoleApp1 } 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); + resultExcelFile.SaveAs(resultExcelPath, true, true); Console.WriteLine("Done. Press any key to quit."); Console.ReadKey(); From 68eca5fdef5f99791d52411a9687293d03bbb378 Mon Sep 17 00:00:00 2001 From: KharchenkoVV Date: Tue, 21 Sep 2021 13:39:03 +0500 Subject: [PATCH 4/4] Changed Images collection storage from temp sheet to memory --- ConsoleApp1/Program.cs | 69 ++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index 5f95a59a..b270c901 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -14,19 +14,32 @@ namespace ConsoleApp1 // .Options; //var context = new AsbCloudDbContext(options); + class ImageInfo + { + public int Id { get; set; } + public byte[] Data { get; set; } + public int Height { get; set; } + public int Width { get; set; } + public IXLAddress TopLeftCellAddress { get; set; } + public int Left { get; set; } + public int Top { get; set; } + } class Program { - private static IXLWorksheet CopyImagesToAnotherSheet(IXLWorksheet sourceSheet, + private static IXLWorksheet CopyImagesToAnotherSheet(IEnumerable imagesInfos, IXLWorksheet resultSheet) { - foreach (var picture in sourceSheet.Pictures) + foreach (var image in imagesInfos) { - resultSheet.AddPicture(picture.ImageStream) + var stream = new MemoryStream(); + stream.Write(image.Data, 0, image.Data.Length); + + resultSheet.AddPicture(stream) .WithPlacement(XLPicturePlacement.Move) - .WithSize(picture.Width, picture.Height) - .MoveTo(resultSheet.Cell(picture.TopLeftCell.Address), - picture.Left, picture.Top); + .WithSize(image.Width, image.Height) + .MoveTo(resultSheet.Cell(image.TopLeftCellAddress), + image.Left, image.Top); } return resultSheet; @@ -49,27 +62,6 @@ namespace ConsoleApp1 return rngData; } - // Изображения не переносятся при вызове метода sheet.CopyTo(). Падает с exception. - // Для этого сначала все изображения переносятся на временный лист "PicsCopy", - // затем удаляются из копируемого листа, копируемый лист копируется в лист-результат - // и после этого из temp листа "PicsCopy" в лист-результат также копируются изображения. - // Temp лист удаляется. - private static void CopySheetToFile(IXLWorksheet currentSheet, XLWorkbook resultExcelFile) - { - var picturesCopySheet = resultExcelFile.AddWorksheet("PicsCopy"); - var copy = currentSheet.Pictures.Select(p => new { buff = p.ImageStream, }); - - 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 @@ -98,6 +90,17 @@ namespace ConsoleApp1 foreach (var sheet in sourceExcelFile.Worksheets) { + var imagesInfos = sheet.Pictures.Select(p => new ImageInfo + { + Id = p.Id, + Data = p.ImageStream.GetBuffer(), + Height = p.Height, + Width = p.Width, + TopLeftCellAddress = p.TopLeftCell.Address, + Left = p.Left, + Top = p.Top + }).ToList(); + if (sheet.Columns().Count() > maxAllowedColumns) { var resultSheet = resultExcelFile.Worksheets.Add(sheet.Name); @@ -115,14 +118,20 @@ namespace ConsoleApp1 resultSheet.Column(i).Width = sheet.Column(i).Width; } - CopyImagesToAnotherSheet(sheet, resultSheet); + CopyImagesToAnotherSheet(imagesInfos, resultSheet); } else - CopySheetToFile(sheet, resultExcelFile); + { + RemovePicturesFromSheet(sheet); + + var resultSheet = sheet.CopyTo(resultExcelFile, sheet.Name); + + CopyImagesToAnotherSheet(imagesInfos, resultSheet); + } } } - resultExcelFile.SaveAs(resultExcelPath, true, true); + resultExcelFile.SaveAs(resultExcelPath); Console.WriteLine("Done. Press any key to quit."); Console.ReadKey();