diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3cc131e..7deac79 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,11 +11,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.4.0 - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v1.9.0 with: - dotnet-version: 3.1.x + dotnet-version: 6.x - name: Install dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f153d2..c1fadc8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,11 +8,11 @@ jobs: name: build, pack & publish runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.4.0 - name: Setup dotnet - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v1.9.0 with: - dotnet-version: 3.1.x + dotnet-version: 6.x - name: Install dependencies run: dotnet restore - name: Build @@ -23,7 +23,7 @@ jobs: # Publish - name: publish on version change id: publish_nuget - uses: rohith/publish-nuget@v2 + uses: brandedoutcast/publish-nuget@v2.5.5 with: PROJECT_FILE_PATH: FastExcel/FastExcel.csproj NUGET_KEY: ${{secrets.NUGET_KEY}} diff --git a/FastExcel.Tests/FastExcel.Tests.csproj b/FastExcel.Tests/FastExcel.Tests.csproj index 18ac8c6..306c751 100644 --- a/FastExcel.Tests/FastExcel.Tests.csproj +++ b/FastExcel.Tests/FastExcel.Tests.csproj @@ -1,21 +1,19 @@  - - netcoreapp3.0 - + net6.0 false - - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - Always @@ -33,5 +31,4 @@ Always - diff --git a/FastExcel.Tests/FastExcelTests.cs b/FastExcel.Tests/FastExcelTests.cs index 5757c5b..91355f8 100644 --- a/FastExcel.Tests/FastExcelTests.cs +++ b/FastExcel.Tests/FastExcelTests.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; + using Xunit; using Xunit.Abstractions; @@ -14,7 +13,7 @@ public class FastExcelTests private static readonly string ResourcesPath = Path.Combine(Environment.CurrentDirectory, "ResourcesTests"); private static readonly string TemplateFilePath = Path.Combine(ResourcesPath, "template.xlsx"); - private static readonly CellRow TestCellRow = new CellRow() + private static readonly CellRow TestCellRow = new() { StringColumn1 = "&", IntegerColumn2 = 45678854, @@ -37,7 +36,7 @@ public void FileNotExist_NewFastExcelWithInvalidInputFile_ThrowsFileNotFoundExce var action = new Action(() => { - using (var fastExcel = new FastExcel(inputFile)) ; + using FastExcel fastExcel = new(inputFile); }); var exception = Assert.Throws(action); @@ -55,7 +54,7 @@ public void FileNotExist_NewFastExcelWithInvalidTemplateFile_ThrowsFileNotFoundE var action = new Action(() => { - using (var fastExcel = new FastExcel(templateFile, outputFile)) ; + using FastExcel fastExcel = new(templateFile, outputFile); }); var exception = Assert.Throws(action); @@ -73,7 +72,7 @@ public void FilesExist_NewFastExcelWithExistOutputFile_ThrowsFileNotFoundExcepti var action = new Action(() => { - using (var fastExcel = new FastExcel(templateFile, outputFile)) ; + using FastExcel fastExcel = new(templateFile, outputFile); }); var exception = Assert.Throws(action); @@ -88,10 +87,8 @@ public void InputFile_ReadExcelWithNullReference_ExceptionIsNull() var action = new Action(() => { - using (var fastExcel = new FastExcel(inputFile, true)) - { - var worksheet = fastExcel.Read(1, 1); - } + using FastExcel fastExcel = new(inputFile, true); + var worksheet = fastExcel.Read(1, 1); }); var exception = Record.Exception(action); @@ -101,19 +98,23 @@ public void InputFile_ReadExcelWithNullReference_ExceptionIsNull() [Fact] public void ThrowsErrorIfInitializedWithStreamAndFileInfoIsAccessed() { - using var inputMemorystream = new MemoryStream(new byte[] {0x1}); + using var inputMemorystream = new MemoryStream(new byte[] { 0x1 }); using var outputMemorystream = new MemoryStream(); + var fastExcel = new FastExcel(inputMemorystream, outputMemorystream); var exception = Assert.Throws(() => fastExcel.ExcelFile); - Assert.Equal($"ExcelFile was not provided", exception.Message); + + Assert.Equal("ExcelFile was not provided", exception.Message); exception = Assert.Throws(() => fastExcel.TemplateFile); - Assert.Equal($"TemplateFile was not provided", exception.Message); + + Assert.Equal("TemplateFile was not provided", exception.Message); } private string FileRead_ReadingSpecialCharactersCore_Read(FileInfo inputFile) { inputFile.Refresh(); using var fastExcel = new FastExcel(inputFile); + var worksheet = fastExcel.Read("sheet1"); var rows = worksheet.Rows; @@ -132,7 +133,6 @@ private string FileRead_ReadingSpecialCharactersCore_Read(FileInfo inputFile) return "Passed"; } - [Fact] public string FileRead_ReadingSpecialCharacters_Read() { @@ -140,7 +140,6 @@ public string FileRead_ReadingSpecialCharacters_Read() return FileRead_ReadingSpecialCharactersCore_Read(inputFilePath); } - [Fact] public string FileWrite_WritingOneRow_Wrote() { @@ -151,13 +150,12 @@ public string FileWrite_WritingOneRow_Wrote() var templateFilePath = new FileInfo(TemplateFilePath); using (var fastExcel = new FastExcel(templateFilePath, inputFilePath)) { - List objectList = new List(); + List objectList = new(); objectList.Add(TestCellRow); fastExcel.Write(objectList, "sheet1", true); } - return FileRead_ReadingSpecialCharactersCore_Read(inputFilePath); } @@ -165,8 +163,10 @@ public string FileWrite_WritingOneRow_Wrote() public string FileUpdate_UpdatingEmptyFile_Updated() { var worksheet = new Worksheet(); - var cells = new List(); - cells.Add(TestCellRow); + var cells = new List + { + TestCellRow + }; worksheet.PopulateRows(cells, usePropertiesAsHeadings: true); var templateFile = new FileInfo(TemplateFilePath); @@ -178,7 +178,6 @@ public string FileUpdate_UpdatingEmptyFile_Updated() fastExcel.Update(worksheet, "Sheet1"); } - return FileRead_ReadingSpecialCharactersCore_Read(inputFile); } @@ -186,7 +185,7 @@ public string FileUpdate_UpdatingEmptyFile_Updated() public string FileUpdate_UpdatingWithOneRow_Updated() { var worksheet = new Worksheet(); - var cells = new List {TestCellRow}; + var cells = new List { TestCellRow }; worksheet.PopulateRows(cells, usePropertiesAsHeadings: true); @@ -204,8 +203,10 @@ public string FileUpdate_UpdatingWithOneRow_Updated() public string FileUpdate_WriteAndUpdatingWithOneRow_Updated() { var worksheet = new Worksheet(); - var cells = new List(); - cells.Add(TestCellRow); + var cells = new List + { + TestCellRow + }; worksheet.PopulateRows(cells, usePropertiesAsHeadings: true); @@ -217,7 +218,6 @@ public string FileUpdate_WriteAndUpdatingWithOneRow_Updated() inputFile.Refresh(); } - //Writing Data One Row using (var fastExcel = new FastExcel(templateFile, inputFile)) { diff --git a/FastExcel/Cell.cs b/FastExcel/Cell.cs index f8fdf8e..0960aa8 100644 --- a/FastExcel/Cell.cs +++ b/FastExcel/Cell.cs @@ -13,7 +13,7 @@ namespace FastExcel public class Cell { /// - /// Column Numnber (Starts at 1) + /// Column Number (Starts at 1) /// public int ColumnNumber { get; set; } @@ -26,12 +26,12 @@ public class Cell /// Defined name or the column letter(s) for column this cell is in /// public string ColumnName { get; } - + /// /// Raw underlying XElement of cell /// public XElement XElement { get; } - + /// /// List of defined names assigned to this cell /// *Does not include names of ranges this cell is within* @@ -45,8 +45,11 @@ public string CellName { get { - if (CellNames.Any()) - return CellNames.FirstOrDefault(); + if (CellNames.Count > 0) + { + return CellNames[0]; + } + return ColumnName + RowNumber; } } @@ -106,7 +109,7 @@ public Cell(XElement cellElement, Worksheet worksheet) { // cellElement.Value will give a concatenated Value + reference/calculation - var node = cellElement.Elements().Where(x => x.Name.LocalName == "v").SingleOrDefault(); + var node = cellElement.Elements().SingleOrDefault(x => x.Name.LocalName == "v"); if (node != null) { @@ -116,7 +119,6 @@ public Cell(XElement cellElement, Worksheet worksheet) { Value = cellElement.Value; } - } } @@ -147,7 +149,7 @@ internal StringBuilder ToXmlString(SharedStrings sharedStrings, int rowNumber) value = sharedStrings.AddString(value.ToString()); } - cell.AppendFormat("", GetExcelColumnName(ColumnNumber), rowNumber, (isString ? " t=\"s\"" : string.Empty)); + cell.AppendFormat("", GetExcelColumnName(ColumnNumber), rowNumber, isString ? " t=\"s\"" : string.Empty); cell.AppendFormat("{0}", value); cell.Append(""); } @@ -215,7 +217,7 @@ public void Merge(Cell cell) } /// - /// + /// Returns a cell's Value as a String /// /// Cell's Value public override string ToString() diff --git a/FastExcel/CellRange.cs b/FastExcel/CellRange.cs index 8bf75eb..758a509 100644 --- a/FastExcel/CellRange.cs +++ b/FastExcel/CellRange.cs @@ -47,7 +47,7 @@ internal CellRange(string reference) // Default value RowStart = 1; - if (range.Contains(":")) + if (range.Contains(':')) { string[] splitRange = range.Split(':'); ColumnStart = splitRange[0].Split('$')[1]; diff --git a/FastExcel/DefinedName.cs b/FastExcel/DefinedName.cs index f8451e9..b1bd192 100644 --- a/FastExcel/DefinedName.cs +++ b/FastExcel/DefinedName.cs @@ -3,7 +3,6 @@ namespace FastExcel { - /// /// Reads/hold information from XElement representing a stored DefinedName /// A defined name is an alias for a cell, multiple cells, a range of cells or multiple ranges of cells @@ -23,7 +22,7 @@ internal DefinedName(XElement e) { try { - WorksheetIndex = Convert.ToInt32(e.Attribute("localSheetId").Value)+1; + WorksheetIndex = Convert.ToInt32(e.Attribute("localSheetId").Value) + 1; } catch (Exception exception) { diff --git a/FastExcel/DefinedNameLoadException.cs b/FastExcel/DefinedNameLoadException.cs index fd5683f..3e8fe54 100644 --- a/FastExcel/DefinedNameLoadException.cs +++ b/FastExcel/DefinedNameLoadException.cs @@ -2,7 +2,6 @@ namespace FastExcel { - /// /// Exception used during loading process of defined names /// @@ -14,7 +13,21 @@ public class DefinedNameLoadException : Exception public DefinedNameLoadException(string message, Exception innerException = null) : base(message, innerException) { + } + + /// + /// Constructor + /// + public DefinedNameLoadException() : base() + { + } + /// + /// Constructor + /// + /// message + public DefinedNameLoadException(string message) : base(message) + { } } } diff --git a/FastExcel/DefinedNamesExtensions.cs b/FastExcel/DefinedNamesExtensions.cs index 768d645..0da72f0 100644 --- a/FastExcel/DefinedNamesExtensions.cs +++ b/FastExcel/DefinedNamesExtensions.cs @@ -8,7 +8,6 @@ namespace FastExcel /// internal static class DefinedNamesExtensions { - /// /// Finds all the cell names for a given cell /// diff --git a/FastExcel/FastExcel.DefinedName.cs b/FastExcel/FastExcel.DefinedName.cs index 991b80a..a2c8eca 100644 --- a/FastExcel/FastExcel.DefinedName.cs +++ b/FastExcel/FastExcel.DefinedName.cs @@ -5,7 +5,7 @@ namespace FastExcel { - partial class FastExcel + public partial class FastExcel { /// /// Dictionary of defined names @@ -48,7 +48,6 @@ private void LoadDefinedNames() var currentDefinedName = new DefinedName(e); _definedNames.Add(currentDefinedName.Key, currentDefinedName); } - } /// @@ -93,12 +92,14 @@ public IEnumerable> GetCellRangesByDefinedName(string definedN /// /// Gets all cells by defined name - /// Like GetCellRangesByCellName, but just retreives all cells in a single list + /// Like GetCellRangesByCellName, but just retrieves all cells in a single list /// /// /// /// +#pragma warning disable RCS1163 // Unused parameter. public IEnumerable GetCellsByDefinedName(string definedName, int? worksheetIndex = null) +#pragma warning restore RCS1163 // Unused parameter. { var cells = new List(); var cellRanges = GetCellRangesByDefinedName(definedName) as List>; @@ -119,7 +120,7 @@ public Cell GetCellByDefinedName(string definedName, int? worksheetIndex = null) { return GetCellsByDefinedName(definedName, worksheetIndex).FirstOrDefault(); } - + /// /// Returns all cells in a column by name, within optional row range /// diff --git a/FastExcel/FastExcel.Read.cs b/FastExcel/FastExcel.Read.cs index 9057449..81d0796 100644 --- a/FastExcel/FastExcel.Read.cs +++ b/FastExcel/FastExcel.Read.cs @@ -37,7 +37,7 @@ private Worksheet Read(int? sheetNumber = null, string sheetName = null, int exi else { worksheet = (from w in Worksheets - where (sheetNumber.HasValue && sheetNumber.Value == w.Index) || + where (sheetNumber == w.Index) || (sheetName == w.Name) select w).SingleOrDefault(); worksheet.Read(existingHeadingRows); diff --git a/FastExcel/FastExcel.Update.cs b/FastExcel/FastExcel.Update.cs index edb7d15..4046540 100644 --- a/FastExcel/FastExcel.Update.cs +++ b/FastExcel/FastExcel.Update.cs @@ -29,9 +29,9 @@ private void Update(Worksheet data, int? sheetNumber = null, string sheetName = Worksheet currentData = Read(sheetNumber, sheetName); currentData.Merge(data); - if(sheetName!=null) + if (sheetName != null) Write(currentData, sheetName); - else if(sheetNumber!=null) + else if (sheetNumber != null) Write(currentData, sheetNumber); else Write(currentData); diff --git a/FastExcel/FastExcel.Write.cs b/FastExcel/FastExcel.Write.cs index fa1aa9a..a468d8a 100644 --- a/FastExcel/FastExcel.Write.cs +++ b/FastExcel/FastExcel.Write.cs @@ -92,7 +92,7 @@ public void Write(IEnumerable objectList, int sheetNumber, bool usePropert public void Write(IEnumerable rows, string sheetName, bool usePropertiesAsHeadings) { var worksheet = new Worksheet(); - worksheet.PopulateRows(rows, 0,usePropertiesAsHeadings); + worksheet.PopulateRows(rows, 0, usePropertiesAsHeadings); Write(worksheet, null, sheetName, 0); } @@ -134,49 +134,46 @@ private void Write(Worksheet worksheet, int? sheetNumber = null, string sheetNam } // Check if ExistingHeadingRows will be overridden by the dataset - if (worksheet.ExistingHeadingRows != 0 && worksheet.Rows.Where(r => r.RowNumber <= worksheet.ExistingHeadingRows).Any()) + if (worksheet.ExistingHeadingRows != 0 && worksheet.Rows.Any(r => r.RowNumber <= worksheet.ExistingHeadingRows)) { throw new Exception("Existing Heading Rows was specified but some or all will be overridden by data rows. Check DataSet.Row.RowNumber against ExistingHeadingRows"); } - using (Stream stream = Archive.GetEntry(worksheet.FileName).Open()) - { - // Open worksheet and read the data at the top and bottom of the sheet - var streamReader = new StreamReader(stream); - worksheet.ReadHeadersAndFooters(streamReader, ref worksheet); + using Stream stream = Archive.GetEntry(worksheet.FileName).Open(); + // Open worksheet and read the data at the top and bottom of the sheet + var streamReader = new StreamReader(stream); + worksheet.ReadHeadersAndFooters(streamReader, ref worksheet); - //Set the stream to the start - stream.Position = 0; + //Set the stream to the start + stream.Position = 0; - // Open the stream so we can override all content of the sheet - var streamWriter = new StreamWriter(stream); + // Open the stream so we can override all content of the sheet + var streamWriter = new StreamWriter(stream); - // TODO instead of saving the headers then writing them back get position where the headers finish then write from there - streamWriter.Write(worksheet.Headers); - if (!worksheet.Template) - { - worksheet.Headers = null; - } + // TODO instead of saving the headers then writing them back get position where the headers finish then write from there + streamWriter.Write(worksheet.Headers); + if (!worksheet.Template) + { + worksheet.Headers = null; + } - SharedStrings.ReadWriteMode = true; + SharedStrings.ReadWriteMode = true; - // Add Rows - foreach (var row in worksheet.Rows) - { - streamWriter.Write(row.ToXmlString(SharedStrings)); - } - SharedStrings.ReadWriteMode = false; + // Add Rows + foreach (var row in worksheet.Rows) + { + streamWriter.Write(row.ToXmlString(SharedStrings)); + } + SharedStrings.ReadWriteMode = false; - //Add Footers - streamWriter.Write(worksheet.Footers); - if (!worksheet.Template) - { - worksheet.Footers = null; - } - streamWriter.Flush(); - stream.SetLength(stream.Position); + //Add Footers + streamWriter.Write(worksheet.Footers); + if (!worksheet.Template) + { + worksheet.Footers = null; } + streamWriter.Flush(); + stream.SetLength(stream.Position); } - } } diff --git a/FastExcel/FastExcel.cs b/FastExcel/FastExcel.cs index cd48058..a6ed98d 100644 --- a/FastExcel/FastExcel.cs +++ b/FastExcel/FastExcel.cs @@ -6,18 +6,20 @@ using System.Text; using System.Xml.Linq; -namespace FastExcel { +namespace FastExcel +{ /// /// Fast Excel /// - public partial class FastExcel : IDisposable { - + public partial class FastExcel : IDisposable + { /// /// Output excel file /// public FileInfo ExcelFile { - get { + get + { if (_excelFile == null) { throw new ApplicationException("ExcelFile was not provided"); @@ -28,7 +30,8 @@ public FileInfo ExcelFile /// /// The template excel file /// - public FileInfo TemplateFile{ + public FileInfo TemplateFile + { get { if (_templateFile == null) @@ -60,12 +63,12 @@ public FileInfo TemplateFile{ internal int MaxSheetNumber { get; set; } /// - /// A list of worksheet indexs to delete + /// A list of worksheet indexes to delete /// private List DeleteWorksheets { get; set; } /// - /// A list of worksheet indexs to insert + /// A list of worksheet indexes to insert /// private List AddWorksheets { get; set; } @@ -74,7 +77,8 @@ public FileInfo TemplateFile{ /// /// location of an existing excel file /// is the file read only - public FastExcel(FileInfo excelFile, bool readOnly = false) : this(null, excelFile, true, readOnly) { + public FastExcel(FileInfo excelFile, bool readOnly = false) : this(null, excelFile, true, readOnly) + { } /// @@ -82,36 +86,43 @@ public FastExcel(FileInfo excelFile, bool readOnly = false) : this(null, excelFi /// /// template location /// location of where a new excel file will be saved to - public FastExcel(FileInfo templateFile, FileInfo excelFile) : this(templateFile, excelFile, false, false) { + public FastExcel(FileInfo templateFile, FileInfo excelFile) : this(templateFile, excelFile, false, false) + { } /// - /// + /// Constructor /// /// /// /// /// - private FastExcel(FileInfo templateFile, FileInfo excelFile, bool updateExisting, bool readOnly = false) { - if (updateExisting) { - if (!excelFile.Exists) { + private FastExcel(FileInfo templateFile, FileInfo excelFile, bool updateExisting, bool readOnly = false) + { + if (updateExisting) + { + if (!excelFile.Exists) + { var exceptionMessage = $"Input file '{excelFile.FullName}' does not exist"; throw new FileNotFoundException(exceptionMessage); } } - else { - if (excelFile.Exists) { + else + { + if (excelFile.Exists) + { var exceptionMessage = $"Output file '{excelFile.FullName}' already exists"; throw new Exception(exceptionMessage); } - if (!templateFile.Exists) { + if (!templateFile.Exists) + { var exceptionMessage = $"Template file '{templateFile.FullName}' was not found"; throw new FileNotFoundException(exceptionMessage); } } _templateFile = templateFile; _excelFile = excelFile; - TemplateFileStream = templateFile != null ? new FileStream(templateFile.FullName, FileMode.Open, FileAccess.Read) : null; + TemplateFileStream = templateFile != null ? new FileStream(templateFile.FullName, FileMode.Open, FileAccess.Read) : null; ExcelFileStream = updateExisting ? new FileStream(excelFile.FullName, FileMode.Open, readOnly ? FileAccess.Read : FileAccess.ReadWrite) : new FileStream(excelFile.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite); @@ -125,7 +136,8 @@ private FastExcel(FileInfo templateFile, FileInfo excelFile, bool updateExisting /// Update an existing excel file stream /// /// - public FastExcel(Stream excelStream) : this(null, excelStream, true) { + public FastExcel(Stream excelStream) : this(null, excelStream, true) + { } /// @@ -135,7 +147,8 @@ public FastExcel(Stream excelStream) : this(null, excelStream, true) { /// Output Excel Stream /// /// - public FastExcel(Stream templateStream, Stream excelStream, bool updateExisting = false, bool readOnly = false) { + public FastExcel(Stream templateStream, Stream excelStream, bool updateExisting = false, bool readOnly = false) + { if (templateStream is FileStream templatefileStream) { _templateFile = new FileInfo(templatefileStream.Name); @@ -151,18 +164,23 @@ public FastExcel(Stream templateStream, Stream excelStream, bool updateExisting CheckFiles(); } - internal void PrepareArchive(bool openSharedStrings = true) { - if (Archive == null) { - if (ReadOnly) { + internal void PrepareArchive(bool openSharedStrings = true) + { + if (Archive == null) + { + if (ReadOnly) + { Archive = new ZipArchive(ExcelFileStream, ZipArchiveMode.Read); } - else { + else + { Archive = new ZipArchive(ExcelFileStream, ZipArchiveMode.Update); } } // Get Strings file - if (SharedStrings == null && openSharedStrings) { + if (SharedStrings == null && openSharedStrings) + { SharedStrings = new SharedStrings(Archive); } } @@ -170,27 +188,34 @@ internal void PrepareArchive(bool openSharedStrings = true) { /// /// Ensure files are ready for use /// - internal void CheckFiles() { - if (_filesChecked) { + internal void CheckFiles() + { + if (_filesChecked) + { return; } - if (UpdateExisting) { - if (ExcelFileStream?.Length == 0) { + if (UpdateExisting) + { + if (ExcelFileStream?.Length == 0) + { throw new Exception("No input file name was supplied"); } } - else { - if (TemplateFileStream == null) { + else + { + if (TemplateFileStream == null) + { throw new Exception("No Template file was supplied"); } - if (ExcelFileStream == null) { - throw new Exception("No Ouput file name was supplied"); + if (ExcelFileStream == null) + { + throw new Exception("No Output file name was supplied"); } - else if (ExcelFileStream.Length > 0) { - var exceptionMessage = $"Output file already exists"; - throw new Exception(exceptionMessage); + else if (ExcelFileStream.Length > 0) + { + throw new Exception("Output file already exists"); } } @@ -200,101 +225,115 @@ internal void CheckFiles() { /// /// Update xl/_rels/workbook.xml.rels file /// - private void UpdateRelations(bool ensureStrings) { + private void UpdateRelations(bool ensureStrings) + { if (!(ensureStrings || - (DeleteWorksheets != null && DeleteWorksheets.Any()) || - (AddWorksheets != null && AddWorksheets.Any()))) { + (DeleteWorksheets?.Any() == true) || + (AddWorksheets?.Any() == true))) + { // Nothing to update return; } - using (Stream stream = Archive.GetEntry("xl/_rels/workbook.xml.rels").Open()) { - XDocument document = XDocument.Load(stream); + using Stream stream = Archive.GetEntry("xl/_rels/workbook.xml.rels").Open(); + XDocument document = XDocument.Load(stream); - if (document == null) { - //TODO error - } + if (document == null) + { + throw new FileLoadException("Excel Document Loaded Was Invalid"); + } - bool update = false; + bool update = false; - List relationshipElements = document.Descendants().Where(d => d.Name.LocalName == "Relationship").ToList(); - int id = relationshipElements.Count; - if (ensureStrings) { - //Ensure SharedStrings - XElement relationshipElement = (from element in relationshipElements - from attribute in element.Attributes() - where attribute.Name == "Target" && attribute.Value.Equals("sharedStrings.xml", StringComparison.OrdinalIgnoreCase) - select element).FirstOrDefault(); + List relationshipElements = document.Descendants().Where(d => d.Name.LocalName == "Relationship").ToList(); + int id = relationshipElements.Count; + if (ensureStrings) + { + //Ensure SharedStrings + XElement relationshipElement = (from element in relationshipElements + from attribute in element.Attributes() + where attribute.Name == "Target" && attribute.Value.Equals("sharedStrings.xml", StringComparison.OrdinalIgnoreCase) + select element).FirstOrDefault(); - if (relationshipElement == null) { - relationshipElement = new XElement(document.Root.GetDefaultNamespace() + "Relationship"); - relationshipElement.Add(new XAttribute("Target", "sharedStrings.xml")); - relationshipElement.Add(new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings")); - relationshipElement.Add(new XAttribute("Id", string.Format("rId{0}", ++id))); + if (relationshipElement == null) + { + relationshipElement = new XElement(document.Root.GetDefaultNamespace() + "Relationship"); + relationshipElement.Add(new XAttribute("Target", "sharedStrings.xml")); + relationshipElement.Add(new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings")); + relationshipElement.Add(new XAttribute("Id", string.Format("rId{0}", ++id))); - document.Root.Add(relationshipElement); - update = true; - } + document.Root.Add(relationshipElement); + update = true; } + } - // Remove all references to sheets from this file as they are not requried - if ((DeleteWorksheets != null && DeleteWorksheets.Any()) || - (AddWorksheets != null && AddWorksheets.Any())) { - XElement[] worksheetElements = (from element in relationshipElements - from attribute in element.Attributes() - where attribute.Name == "Type" && attribute.Value == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" - select element).ToArray(); - for (int i = worksheetElements.Length - 1; i > 0; i--) { - worksheetElements[i].Remove(); - update = true; - } + // Remove all references to sheets from this file as they are not required + if ((DeleteWorksheets?.Any() == true) || + (AddWorksheets?.Any() == true)) + { + XElement[] worksheetElements = (from element in relationshipElements + from attribute in element.Attributes() + where attribute.Name == "Type" && attribute.Value == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" + select element).ToArray(); + for (int i = worksheetElements.Length - 1; i > 0; i--) + { + worksheetElements[i].Remove(); + update = true; } + } - if (update) { - // Set the stream to the start - stream.Position = 0; - // Clear the stream - stream.SetLength(0); - - // Open the stream so we can override all content of the sheet - StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8); - document.Save(streamWriter); - streamWriter.Flush(); - } + if (update) + { + // Set the stream to the start + stream.Position = 0; + // Clear the stream + stream.SetLength(0); + + // Open the stream so we can override all content of the sheet + StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8); + document.Save(streamWriter); + streamWriter.Flush(); } } /// /// Update xl/workbook.xml file /// - private string[] UpdateWorkbook() { - if (!(DeleteWorksheets != null && DeleteWorksheets.Any() || - (AddWorksheets != null && AddWorksheets.Any()))) { + /// [Optional(default false)]force a re-write of all sheets + private string[] UpdateWorkbook(bool update = false) + { + if (!((DeleteWorksheets?.Any() == true) || + (AddWorksheets?.Any() == true))) + { // Nothing to update return null; } - List sheetNames = new List(); - using (Stream stream = Archive.GetEntry("xl/workbook.xml").Open()) { + List sheetNames = new List(); + using (Stream stream = Archive.GetEntry("xl/workbook.xml").Open()) + { XDocument document = XDocument.Load(stream); - if (document == null) { + if (document == null) + { throw new Exception("Unable to load workbook.xml"); } - bool update = false; - RenameAndRebildWorksheetProperties((from sheet in document.Descendants() - where sheet.Name.LocalName == "sheet" - select sheet).ToArray()); + where sheet.Name.LocalName == "sheet" + select sheet).ToArray()); + + //bool update = false; //made this into an optional function parameter instead. - if (update) { + if (update) + { // Re number sheet ids XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; int id = 1; foreach (XElement sheetElement in (from sheet in document.Descendants() - where sheet.Name.LocalName == "sheet" - select sheet)) { + where sheet.Name.LocalName == "sheet" + select sheet)) + { sheetElement.SetAttributeValue(r + "id", string.Format("rId{0}", id++)); sheetNames.Add(sheetElement.Attribute("name").Value); } @@ -314,13 +353,14 @@ private string[] UpdateWorkbook() { return sheetNames.ToArray(); } - /// /// If sheets have been added or deleted, sheets need to be renamed /// - private void RenameAndRebildWorksheetProperties(XElement[] sheets) { - if (!((DeleteWorksheets != null && DeleteWorksheets.Any()) || - (AddWorksheets != null && AddWorksheets.Any()))) { + private void RenameAndRebildWorksheetProperties(XElement[] sheets) + { + if (!((DeleteWorksheets?.Any() == true) || + (AddWorksheets?.Any() == true))) + { // Nothing to update return; } @@ -328,39 +368,47 @@ private void RenameAndRebildWorksheetProperties(XElement[] sheets) { XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; List sheetProperties = (from sheet in sheets - select new WorksheetProperties - () { - SheetId = int.Parse(sheet.Attribute("sheetId").Value), - Name = sheet.Attribute("name").Value, - CurrentIndex = int.Parse(sheet.Attribute(r + "id").Value) - }).ToList(); + select new WorksheetProperties + () + { + SheetId = int.Parse(sheet.Attribute("sheetId").Value), + Name = sheet.Attribute("name").Value, + CurrentIndex = int.Parse(sheet.Attribute(r + "id").Value) + }).ToList(); // Remove deleted worksheets to sheetProperties - if (DeleteWorksheets != null && DeleteWorksheets.Any()) { - foreach (var item in DeleteWorksheets) { + if (DeleteWorksheets?.Any() == true) + { + foreach (var item in DeleteWorksheets) + { WorksheetProperties sheetToDelete = (from sp in sheetProperties - where sp.SheetId == item - select sp).FirstOrDefault(); + where sp.SheetId == item + select sp).FirstOrDefault(); - if (sheetToDelete != null) { + if (sheetToDelete != null) + { sheetProperties.Remove(sheetToDelete); } } } // Add new worksheets to sheetProperties - if (AddWorksheets != null && AddWorksheets.Any()) { + if (AddWorksheets?.Any() == true) + { // Add the sheets in reverse, this will add them correctly with less work - foreach (var item in AddWorksheets.Reverse()) { + foreach (var item in AddWorksheets.Reverse()) + { WorksheetProperties previousSheet = (from sp in sheetProperties - where sp.SheetId == item.InsertAfterSheetId - select sp).FirstOrDefault(); + where sp.SheetId == item.InsertAfterSheetId + select sp).FirstOrDefault(); - if (previousSheet == null) { + if (previousSheet == null) + { throw new Exception(string.Format("Sheet name {0} cannot be added because the insertAfterSheetNumber or insertAfterSheetName is now invalid", item.Name)); } - WorksheetProperties newWorksheet = new WorksheetProperties() { + WorksheetProperties newWorksheet = new WorksheetProperties() + { SheetId = item.SheetId, Name = item.Name, CurrentIndex = 0 // TODO Something?? @@ -370,10 +418,13 @@ private void RenameAndRebildWorksheetProperties(XElement[] sheets) { } int index = 1; - foreach (WorksheetProperties worksheet in sheetProperties) { - if (worksheet.CurrentIndex != index) { + foreach (WorksheetProperties worksheet in sheetProperties) + { + if (worksheet.CurrentIndex != index) + { ZipArchiveEntry entry = Archive.GetEntry(Worksheet.GetFileName(worksheet.CurrentIndex)); - if (entry == null) { + if (entry == null) + { // TODO better message throw new Exception("Worksheets could not be rebuilt"); } @@ -386,83 +437,97 @@ private void RenameAndRebildWorksheetProperties(XElement[] sheets) { /// /// Update [Content_Types].xml file /// - private void UpdateContentTypes(bool ensureStrings) { + /// + private void UpdateContentTypes(bool ensureStrings) + { if (!(ensureStrings || - (DeleteWorksheets != null && DeleteWorksheets.Any()) || - (AddWorksheets != null && AddWorksheets.Any()))) { + (DeleteWorksheets?.Count > 0) || + (AddWorksheets?.Any() == true))) + { // Nothing to update return; } - using (Stream stream = Archive.GetEntry("[Content_Types].xml").Open()) { - XDocument document = XDocument.Load(stream); + using Stream stream = Archive.GetEntry("[Content_Types].xml").Open(); + XDocument document = XDocument.Load(stream); - if (document == null) { - //TODO error - } - - bool update = false; - List overrideElements = document.Descendants().Where(d => d.Name.LocalName == "Override").ToList(); - - //Ensure SharedStrings - if (ensureStrings) { - XElement overrideElement = (from element in overrideElements - from attribute in element.Attributes() - where attribute.Name == "PartName" && attribute.Value.Equals("/xl/sharedStrings.xml", StringComparison.OrdinalIgnoreCase) - select element).FirstOrDefault(); + if (document == null) + { + throw new FileLoadException("Content Types Do Not Exist"); + } - if (overrideElement == null) { - overrideElement = new XElement(document.Root.GetDefaultNamespace() + "Override"); - overrideElement.Add(new XAttribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml")); - overrideElement.Add(new XAttribute("PartName", "/xl/sharedStrings.xml")); + bool update = false; + List overrideElements = document.Descendants().Where(d => d.Name.LocalName == "Override").ToList(); - document.Root.Add(overrideElement); - update = true; - } - } + //Ensure SharedStrings + if (ensureStrings) + { + XElement overrideElement = (from element in overrideElements + from attribute in element.Attributes() + where attribute.Name == "PartName" && attribute.Value.Equals("/xl/sharedStrings.xml", + StringComparison.OrdinalIgnoreCase) + select element).FirstOrDefault(); - if (DeleteWorksheets != null && DeleteWorksheets.Any()) { - foreach (var item in DeleteWorksheets) { - // the file name is different for each xml file - string fileName = string.Format("/xl/worksheets/sheet{0}.xml", item); - - XElement overrideElement = (from element in overrideElements - from attribute in element.Attributes() - where attribute.Name == "PartName" && attribute.Value == fileName - select element).FirstOrDefault(); - if (overrideElement != null) { - overrideElement.Remove(); - update = true; - } - } + if (overrideElement == null) + { + overrideElement = new XElement(document.Root.GetDefaultNamespace() + "Override"); + overrideElement.Add(new XAttribute( + "ContentType", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml")); + overrideElement.Add(new XAttribute("PartName", "/xl/sharedStrings.xml")); + + document.Root.Add(overrideElement); + update = true; } + } - if (AddWorksheets != null && AddWorksheets.Any()) { - foreach (var item in AddWorksheets) { - // the file name is different for each xml file - string fileName = string.Format("/xl/worksheets/sheet{0}.xml", item.SheetId); - - XElement overrideElement = new XElement(document.Root.GetDefaultNamespace() + "Override"); - overrideElement.Add(new XAttribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml")); - overrideElement.Add(new XAttribute("PartName", fileName)); + if (DeleteWorksheets?.Any() == true) + { + foreach (var item in DeleteWorksheets) + { + // the file name is different for each XML file + string fileName = string.Format("/xl/worksheets/sheet{0}.xml", item); - document.Root.Add(overrideElement); + XElement overrideElement = (from element in overrideElements + from attribute in element.Attributes() + where attribute.Name == "PartName" && attribute.Value == fileName + select element).FirstOrDefault(); + if (overrideElement != null) + { + overrideElement.Remove(); update = true; } } + } - if (update) { - // Set the stream to the start - stream.Position = 0; - // Clear the stream - stream.SetLength(0); + if (AddWorksheets?.Any() == true) + { + foreach (var item in AddWorksheets) + { + // the file name is different for each XML file + string fileName = string.Format("/xl/worksheets/sheet{0}.xml", item.SheetId); - // Open the stream so we can override all content of the sheet - StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8); - document.Save(streamWriter); - streamWriter.Flush(); + XElement overrideElement = new XElement(document.Root.GetDefaultNamespace() + "Override"); + overrideElement.Add(new XAttribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml")); + overrideElement.Add(new XAttribute("PartName", fileName)); + + document.Root.Add(overrideElement); + update = true; } } + + if (update) + { + // Set the stream to the start + stream.Position = 0; + // Clear the stream + stream.SetLength(0); + + // Open the stream so we can override all content of the sheet + StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8); + document.Save(streamWriter); + streamWriter.Flush(); + } } /// @@ -470,14 +535,19 @@ from attribute in element.Attributes() /// /// /// 1 based index of sheet or 0 if not found - public int GetWorksheetIndexFromName(string name) { + public int GetWorksheetIndexFromName(string name) + { return (from worksheet in Worksheets where worksheet.Name == name select worksheet.Index).FirstOrDefault(); } /// /// Update docProps/app.xml file /// - private void UpdateDocPropsApp(string[] sheetNames) { + /// +#pragma warning disable RCS1163 // Unused parameter. + private static void UpdateDocPropsApp(string[] sheetNames) +#pragma warning restore RCS1163 // Unused parameter. + { /* if (sheetNames == null || !sheetNames.Any()) { // Nothing to update @@ -552,7 +622,8 @@ from attribute in sheet.Attributes() /// /// Saves any pending changes to the Excel stream and adds/updates associated files if needed /// - public void Dispose() { + public void Dispose() + { Dispose(true); GC.SuppressFinalize(this); } @@ -560,16 +631,20 @@ public void Dispose() { /// /// Main disposal function /// - protected virtual void Dispose(bool disposing) { - if (Archive == null) { + protected virtual void Dispose(bool disposing) + { + if (Archive == null) + { return; } - if (Archive.Mode != ZipArchiveMode.Read) { + if (Archive.Mode != ZipArchiveMode.Read) + { bool ensureSharedStrings = false; // Update or create xl/sharedStrings.xml file - if (SharedStrings != null) { + if (SharedStrings != null) + { ensureSharedStrings = SharedStrings.PendingChanges; SharedStrings.Write(); } diff --git a/FastExcel/FastExcel.csproj b/FastExcel/FastExcel.csproj index 2638e94..db32b94 100644 --- a/FastExcel/FastExcel.csproj +++ b/FastExcel/FastExcel.csproj @@ -1,25 +1,24 @@  - - netstandard2.0 + netstandard2.1 FastExcel Jono Clarnette, Ahmed Massoud A fast way to read and write to Excel *.xlsx files without using the Open XML library. false Copyright 2016-2020 Jono Clarnette fast excel xlsx read write - https://github.com/ahmedwalid05/FastExcel/blob/master/LICENSE + https://github.com/ahmedwalid05/FastExcel/blob/master/LICENSE + https://github.com/ahmedwalid05/FastExcel https://github.com/ahmedwalid05/FastExcel en True - 1.0.0.0 - 1.0.0.0 - 3.0.13 + 1.1.0.0 + 1.1.0.0 + 3.1.0 bin\$(Configuration)\$(TargetFramework)\FastExcel.xml - \ No newline at end of file diff --git a/FastExcel/Row.cs b/FastExcel/Row.cs index 71af685..e54f8a0 100644 --- a/FastExcel/Row.cs +++ b/FastExcel/Row.cs @@ -50,7 +50,7 @@ public Row(XElement rowElement, Worksheet worksheet) { throw new Exception("Row Number not found", ex); } - + if (rowElement.HasElements) { Cells = GetCells(rowElement, worksheet); @@ -70,7 +70,7 @@ public Cell GetCellByColumnName(string columnName) // // Get all cells in this row. // - private IEnumerable GetCells(XElement rowElement, Worksheet worksheet) + private static IEnumerable GetCells(XElement rowElement, Worksheet worksheet) { foreach (XElement cellElement in rowElement.Elements()) { @@ -85,7 +85,7 @@ internal StringBuilder ToXmlString(SharedStrings sharedStrings) { var row = new StringBuilder(); - if (Cells != null && Cells.Any()) + if (Cells?.Any() == true) { row.AppendFormat("", RowNumber); try @@ -129,8 +129,8 @@ internal void Merge(Row row) // Sort Cells = (from c in outputList - orderby c.ColumnNumber - select c); + orderby c.ColumnNumber + select c); } } } diff --git a/FastExcel/SharedStrings.cs b/FastExcel/SharedStrings.cs index 202975e..3079727 100644 --- a/FastExcel/SharedStrings.cs +++ b/FastExcel/SharedStrings.cs @@ -13,11 +13,11 @@ namespace FastExcel public class SharedStrings { //A dictionary is a lot faster than a list - private Dictionary StringDictionary { get; set; } + private Dictionary StringDictionary { get; } private Dictionary StringArray { get; set; } - private bool SharedStringsExists { get; set; } - private ZipArchive ZipArchive { get; set; } + private bool SharedStringsExists { get; } + private ZipArchive ZipArchive { get; } /// /// Is there any pending changes @@ -35,43 +35,41 @@ internal SharedStrings(ZipArchive archive) SharedStringsExists = true; - if (!ZipArchive.Entries.Where(entry => entry.FullName == "xl/sharedStrings.xml").Any()) + if (!ZipArchive.Entries.Any(entry => entry.FullName == "xl/sharedStrings.xml")) { StringDictionary = new Dictionary(); SharedStringsExists = false; return; } - using (Stream stream = ZipArchive.GetEntry("xl/sharedStrings.xml").Open()) + using Stream stream = ZipArchive.GetEntry("xl/sharedStrings.xml").Open(); + if (stream == null) { - if (stream == null) - { - StringDictionary = new Dictionary(); - SharedStringsExists = false; - return; - } - - var document = XDocument.Load(stream); + StringDictionary = new Dictionary(); + SharedStringsExists = false; + return; + } - if (document == null) - { - StringDictionary = new Dictionary(); - SharedStringsExists = false; - return; - } + var document = XDocument.Load(stream); - // int i = 0; - // StringDictionary = document.Descendants().Where(d => d.Name.LocalName == "t").Select(e => e.Value).Select(XmlConvert.DecodeName).to - // .ToDictionary(k => k, v => i++); - int i = 0; + if (document == null) + { StringDictionary = new Dictionary(); - List StringList = new List(); - StringList = document.Descendants().Where(d => d.Name.LocalName == "t").Select(e => XmlConvert.DecodeName(e.Value)).ToList(); - foreach (string currentString in StringList) - { - if (!StringDictionary.ContainsKey(currentString)) - StringDictionary.Add(currentString, i++); - } + SharedStringsExists = false; + return; + } + + // int i = 0; + // StringDictionary = document.Descendants().Where(d => d.Name.LocalName == "t").Select(e => e.Value).Select(XmlConvert.DecodeName).to + // .ToDictionary(k => k, v => i++); + int i = 0; + StringDictionary = new Dictionary(); + List StringList = new List(); + StringList = document.Descendants().Where(d => d.Name.LocalName == "t").Select(e => XmlConvert.DecodeName(e.Value)).ToList(); + foreach (string currentString in StringList) + { + if (!StringDictionary.ContainsKey(currentString)) + StringDictionary.Add(currentString, i++); } } diff --git a/FastExcel/Worksheet.cs b/FastExcel/Worksheet.cs index 38b9a5b..19a3477 100644 --- a/FastExcel/Worksheet.cs +++ b/FastExcel/Worksheet.cs @@ -1,12 +1,12 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Data; +using System.IO; using System.Linq; using System.Reflection; using System.Text; -using System.IO; using System.Xml.Linq; -using System.Collections; -using System.Data; namespace FastExcel { @@ -39,11 +39,11 @@ public class Worksheet /// public int ExistingHeadingRows { get; set; } private int? InsertAfterIndex { get; set; } - + /// /// Template /// - public bool Template { get; set; } + public bool Template { get; } internal string Headers { get; set; } internal string Footers { get; set; } @@ -71,6 +71,7 @@ internal static string GetFileName(int index) private const string DEFAULT_HEADERS = ""; private const string DEFAULT_FOOTERS = ""; + private const string SINGLE_SHEET = "worksheets/sheet.xml"; /// /// Constructor @@ -90,7 +91,7 @@ public Worksheet(FastExcel fastExcel) /// public void PopulateRows(IEnumerable rows, int existingHeadingRows = 0, bool usePropertiesAsHeadings = false) { - if ((rows.FirstOrDefault() as IEnumerable) == null) + if (!(rows.FirstOrDefault() is IEnumerable)) { PopulateRowsFromObjects(rows, existingHeadingRows, usePropertiesAsHeadings); } @@ -101,7 +102,7 @@ public void PopulateRows(IEnumerable rows, int existingHeadingRows = 0, bo } /// - /// Populate rows from datatable + /// Populate rows from data table /// public void PopulateRowsFromDataTable(DataTable table, int existingHeadingRows = 0) { @@ -219,6 +220,49 @@ private void PopulateRowsFromIEnumerable(IEnumerable> rows, Rows = newRows; } + + /// + /// Convert Rows back to Object + /// + /// + /// + /// + public List MapToObject(IEnumerable rows, int existingHeadingRows = 0) + { + int rowNumber = existingHeadingRows + 1; + + var collectionType = typeof(List<>).MakeGenericType(typeof(T)); + var list = Activator.CreateInstance(collectionType); + + var addMethod = collectionType.GetMethod("Add"); + + // Get all property for map + IEnumerable properties = typeof(T).GetRuntimeProperties(); + foreach (Row row in rows.Skip(existingHeadingRows)) + { + int propertyIndex = 1; + var objectInstance = Activator.CreateInstance(typeof(T)); + foreach (PropertyInfo propertyInfo in properties) + { + var colName = Cell.GetExcelColumnName(propertyIndex); + if (row.Cells.Where(x => x.ColumnName == colName && x.RowNumber == rowNumber).Any()) + { + var value = row.Cells.Where(x => x.ColumnName == colName && x.RowNumber == rowNumber).SingleOrDefault().Value; + if (propertyInfo.PropertyType == typeof(DateTime)) + { + double dateValue; + if (double.TryParse(value.ToString(), out dateValue)) + value = DateTime.FromOADate(dateValue); + } + propertyInfo.SetValue(objectInstance, Convert.ChangeType(value,propertyInfo.PropertyType)); + } + propertyIndex++; + } + rowNumber++; + addMethod.Invoke(list, new object[] { objectInstance }); + } + return (List)list; + } /// /// Add a row using a collection of value objects @@ -248,7 +292,7 @@ public void AddRow(params object[] cellValues) } var row = new Row(Rows.Count() + 1, cells); - (Rows as List).Add(row); + (Rows as List)?.Add(row); } /// @@ -270,7 +314,7 @@ public void AddValue(int rowNumber, int columnNumber, object value) { cell = new Cell(columnNumber, value); row = new Row(rowNumber, new List { cell }); - (Rows as List).Add(row); + (Rows as List)?.Add(row); } if (cell == null) @@ -282,10 +326,9 @@ public void AddValue(int rowNumber, int columnNumber, object value) if (cell == null) { cell = new Cell(columnNumber, value); - (row.Cells as List).Add(cell); + (row.Cells as List)?.Add(cell); } } - } /// @@ -295,7 +338,7 @@ public void AddValue(int rowNumber, int columnNumber, object value) public void Merge(Worksheet data) { // Merge headings - if (Headings == null || !Headings.Any()) + if (Headings?.Any() != true) { Headings = data.Headings; } @@ -355,10 +398,11 @@ public void Read(int existingHeadingRows = 0) IEnumerable rows = null; var headings = new List(); - using (Stream stream = FastExcel.Archive.GetEntry(FileName).Open()) + string filename = DecideFilename(); + using (Stream stream = FastExcel.Archive.GetEntry(filename).Open()) { var document = XDocument.Load(stream); - int skipRows = 0; + const int skipRows = 0; var rowElement = document.Descendants().FirstOrDefault(d => d.Name.LocalName == "row"); if (rowElement != null) @@ -379,6 +423,18 @@ public void Read(int existingHeadingRows = 0) Rows = rows; } + /// + /// Check if single sheet exists, and use that name accordingly. + /// + /// Filename + private string DecideFilename() + { + var filename = FastExcel.Archive.Entries.FirstOrDefault(x => x.FullName.Contains(SINGLE_SHEET))?.FullName; + if (filename == null) + filename = FileName; + return filename; + } + /// /// Returns cells using provided range /// @@ -439,16 +495,15 @@ internal void ReadHeadersAndFooters(StreamReader stream, ref Worksheet worksheet while (stream.Peek() >= 0) { string line = stream.ReadLine(); - int currentLineIndex = 0; - + int currentLineIndex; if (!headersComplete) { if (line.Contains("")) { currentLineIndex = line.IndexOf(""); - headers.Append(line.Substring(0, currentLineIndex)); + headers.Append(line, 0, currentLineIndex); //remove the read section from line - line = line.Substring(currentLineIndex, line.Length - currentLineIndex); + line = line[currentLineIndex..]; headers.Append(""); @@ -463,9 +518,9 @@ internal void ReadHeadersAndFooters(StreamReader stream, ref Worksheet worksheet else if (line.Contains("")) { currentLineIndex = line.IndexOf(""); - headers.Append(line.Substring(0, currentLineIndex)); + headers.Append(line, 0, currentLineIndex); //remove the read section from line - line = line.Substring(currentLineIndex, line.Length - currentLineIndex); + line = line[currentLineIndex..]; headers.Append(""); @@ -497,26 +552,26 @@ internal void ReadHeadersAndFooters(StreamReader stream, ref Worksheet worksheet { int index = line.IndexOf("") + "".Length; - headers.Append(line.Substring(index, currentLineIndex - index)); + headers.Append(line, index, currentLineIndex - index); //remove the read section from line - line = line.Substring(currentLineIndex, line.Length - currentLineIndex); + line = line[currentLineIndex..]; existingHeadingRows--; } else { int index = line.IndexOf("")) { currentLineIndex = line.IndexOf("") + "".Length; - headers.Append(line.Substring(0, currentLineIndex)); + headers.Append(line, 0, currentLineIndex); //remove the read section from line - line = line.Substring(currentLineIndex, line.Length - currentLineIndex); + line = line[currentLineIndex..]; existingHeadingRows--; } } @@ -533,13 +588,13 @@ internal void ReadHeadersAndFooters(StreamReader stream, ref Worksheet worksheet if (line.Contains("")) { int index = line.IndexOf("") + "".Length; - var foot = line.Substring(index, line.Length - index); + var foot = line[index..]; footers.Append(foot); } else if (line.Contains("")) { int index = line.IndexOf("") + "".Length; - footers.Append(line.Substring(index, line.Length - index)); + footers.Append(line, index, line.Length - index); } else { @@ -551,7 +606,6 @@ internal void ReadHeadersAndFooters(StreamReader stream, ref Worksheet worksheet worksheet.Footers = footers.ToString(); } - /// /// Get worksheet file name from xl/workbook.xml /// @@ -672,7 +726,7 @@ internal void ValidateNewWorksheet(FastExcel fastExcel, int? insertAfterSheetNum throw new Exception(string.Format("Worksheet name '{0}' already exists", Name)); } - fastExcel.MaxSheetNumber += 1; + fastExcel.MaxSheetNumber++; Index = fastExcel.MaxSheetNumber; if (string.IsNullOrEmpty(Headers)) @@ -706,4 +760,4 @@ internal WorksheetAddSettings AddSettings } } } -} \ No newline at end of file +} diff --git a/README.md b/README.md index cf0ded6..4bda622 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,13 @@ - Does not use the Open XML SDK to interact with the data but going directly and editing the underlying xml files. - This project is not intended to be a replacement for full featured Excel packages with things like formatting, just light weight fast way of interacting with data in Excel. +#### Version 3.1 +- Contribute using Visual Studio 2019 +- Built using [.NetStandard](https://docs.microsoft.com/en-us/dotnet/standard/library) 2.1 targeting: + - .Net Standard 2.1 + - .Net 5.0 + - .Net 6.0 + #### Version 3 - Contribute using Visual Studio 2017 - Built using [.NetStandard](https://docs.microsoft.com/en-us/dotnet/standard/library) 2 targeting: