[Optimization] SaveAs by datareader support dimension #231

This commit is contained in:
WeiLin 2022-09-18 22:49:00 +08:00
parent b01e28c5df
commit 2e9c310396
9 changed files with 129 additions and 55 deletions

View File

@ -5,7 +5,7 @@ VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniExcelLibs", "src\MiniExcel\MiniExcelLibs.csproj", "{097903C9-1F81-4427-B4C8-530CB59687B8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2AFABF2E-D6C3-4983-B43A-76ADA2BB2876}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs and setting", "Docs and setting", "{2AFABF2E-D6C3-4983-B43A-76ADA2BB2876}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
.gitignore = .gitignore
@ -21,7 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CC1E0601-AEC
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{359A7094-3353-48F2-B3E1-FE9E59698318}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{3E370222-8E9E-45E8-8DCD-E5F41EE52A39}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Releases", "Releases", "{3E370222-8E9E-45E8-8DCD-E5F41EE52A39}"
ProjectSection(SolutionItems) = preProject
docs\README.md = docs\README.md
docs\README.zh-CN.md = docs\README.zh-CN.md

View File

@ -22,7 +22,14 @@
---
### 1.27.0
- [Optimization] SaveAs by datareader support dimension #231 (via @shps951023)
### 1.26.7
- [OPT] Reduce memory allocation when using MemoryStream #427 (via @cupsos)
- [OPT] Add System.Memory pacakge #427 (via @cupsos)
- [OPT] Reduce memory allocation in GetImageFormat() #427 (via @cupsos)

View File

@ -25,7 +25,14 @@
---
### 1.27.0
- [Optimization] SaveAs by datareader 支持 dimension #231 (via @shps951023)
### 1.26.7
- [OPT] 减少 memory allocation 使用 MemoryStream #427 (via @cupsos)
- [OPT] 添加 System.Memory pacakge #427 (via @cupsos)
- [OPT] 减少 memory allocation in GetImageFormat() #427 (via @cupsos)

View File

@ -25,7 +25,13 @@
---
### 1.27.0
- [Optimization] SaveAs by datareader 支持 dimension #231 (via @shps951023)
### 1.26.7
- [OPT] 減少 memory allocation 使用 MemoryStream #427 (via @cupsos)
- [OPT] 添加 System.Memory pacakge #427 (via @cupsos)
- [OPT] 減少 memory allocation in GetImageFormat() #427 (via @cupsos)

View File

@ -1,31 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0;net5.0</TargetFrameworks>
<Version>1.26.7</Version>
<Version>1.27.0</Version>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>MiniExcel</AssemblyName>
<Title>MiniExcel</Title>
<Product>MiniExcel</Product>
<PackageTags>excel;xlsx;csv;micro-helper;mini;openxml;helper;</PackageTags>
<Description>Fast, Low-Memory, Easy Excel .NET helper to import/export/template spreadsheet
<Description>
Fast, Low-Memory, Easy Excel .NET helper to import/export/template spreadsheet
Github : https://github.com/shps951023/MiniExcel
Gitee : https://gitee.com/dotnetchina/MiniExcel
Issues : https://github.com/shps951023/MiniExcel/issues
Todo : https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true
</Description>
Github : https://github.com/MiniExcel/MiniExcel
Gitee : https://gitee.com/dotnetchina/MiniExcel
Issues : https://github.com/MiniExcel/MiniExcel/issues
Todo : https://github.com/MiniExcel/MiniExcel/projects/1?fullscreen=true
</Description>
<Authors>LIN,WEI-HAN</Authors>
<PackageId>MiniExcel</PackageId>
<Copyright>LIN,WEI-HAN, 2021 onwards</Copyright>
<NeutralLanguage>en</NeutralLanguage>
<license>https://raw.githubusercontent.com/shps951023/MiniExcel/master/LICENSE</license>
<license>https://raw.githubusercontent.com/MiniExcel/MiniExcel/master/LICENSE</license>
<RootNamespace>MiniExcelLibs</RootNamespace>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/shps951023/MiniExcel</PackageProjectUrl>
<RepositoryUrl>https://github.com/shps951023/MiniExcel</RepositoryUrl>
<PackageProjectUrl>https://github.com/MiniExcel/MiniExcel</PackageProjectUrl>
<RepositoryUrl>https://github.com/MiniExcel/MiniExcel</RepositoryUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageReleaseNotes>Please Check [Release Notes](https://github.com/shps951023/MiniExcel/tree/master/docs)</PackageReleaseNotes>
<PackageReleaseNotes>Please Check [Release Notes](https://github.com/MiniExcel/MiniExcel/tree/master/docs)</PackageReleaseNotes>
<RepositoryType>Github</RepositoryType>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461'">
@ -35,14 +36,14 @@ Todo : https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true
<Reference Include="System.IO.Compression" />
</ItemGroup>
<ItemGroup>
<None Update="icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="icon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45' Or '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<ItemGroup>
<None Include="icon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45' Or '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
</Project>

View File

@ -54,7 +54,9 @@ namespace MiniExcelLibs.OpenXml
public ExcelOpenXmlSheetWriter(Stream stream, object value, string sheetName, IConfiguration configuration, bool printHeader)
{
this._stream = stream;
this._archive = new MiniExcelZipArchive(_stream, ZipArchiveMode.Create, true, _utf8WithBom);
// Why ZipArchiveMode.Update not ZipArchiveMode.Create?
// R : Mode create - ZipArchiveEntry does not support seeking.'
this._archive = new MiniExcelZipArchive(_stream, ZipArchiveMode.Update, true, _utf8WithBom);
this._configuration = configuration as OpenXmlConfiguration ?? OpenXmlConfiguration.DefaultConfig;
this._printHeader = printHeader;
this._value = value;
@ -579,15 +581,13 @@ namespace MiniExcelLibs.OpenXml
private void GenerateSheetByIDataReader(MiniExcelStreamWriter writer, IDataReader reader)
{
var xy = ExcelOpenXmlUtils.ConvertCellToXY("A1"); /*TODO:code smell*/
long dimensionWritePosition = 0;
writer.Write($@"<?xml version=""1.0"" encoding=""utf-8""?><x:worksheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">");
var yIndex = xy.Item2;
var xIndex = 0;
{
// TODO: dimension
//var maxRowIndex = value.Rows.Count + (printHeader && value.Rows.Count > 0 ? 1 : 0);
//var maxColumnIndex = value.Columns.Count;
//writer.Write($@"<x:dimension ref=""{GetDimensionRef(maxRowIndex, maxColumnIndex)}""/>");
dimensionWritePosition = writer.WriteAndFlush($@"<x:dimension ref=""");
writer.Write($@" />"); // end of code will be replaced
writer.Write("<x:sheetData>");
int fieldCount = reader.FieldCount;
if (_printHeader)
@ -623,7 +623,10 @@ namespace MiniExcelLibs.OpenXml
writer.Write("</x:sheetData>");
if (_configuration.AutoFilter)
writer.Write($"<x:autoFilter ref=\"A1:{ExcelOpenXmlUtils.ConvertXyToCell((xIndex-1)/*TODO:code smell*/, yIndex-1)}\" />");
writer.Write("</x:worksheet>");
writer.WriteAndFlush("</x:worksheet>");
writer.SetPosition(dimensionWritePosition);
writer.WriteAndFlush($@"A1:{ExcelOpenXmlUtils.ConvertXyToCell((xIndex - 1)/*TODO:code smell*/, yIndex - 1)}""");
}
private static void WriteC(MiniExcelStreamWriter writer, string r, string columnName)

View File

@ -8,53 +8,42 @@ namespace MiniExcelLibs.OpenXml
{
private readonly Stream _stream;
private readonly Encoding _encoding;
private readonly StreamWriter _streamWriter;
internal readonly StreamWriter _streamWriter;
private bool disposedValue;
//private byte[] _cacheValueBytes;
public MiniExcelStreamWriter(Stream stream,Encoding encoding, int bufferSize)
{
this._stream = stream;
this._encoding = encoding;
this._streamWriter = new StreamWriter(stream, this._encoding, bufferSize);
}
public void Write(string content,bool flushImmediately=false)
public void Write(string content)
{
if (string.IsNullOrEmpty(content))
return;
//if (flushImmediately)
//else
//_cacheValueBytes.CopyTo
//TODO:
//var bytes = this._encoding.GetBytes(content);
//this._stream.Write(bytes, 0, bytes.Length);
this._streamWriter.Write(content);
}
public long WriteAndFlush(string content)
{
this.Write(content);
this._streamWriter.Flush();
return this._streamWriter.BaseStream.Position;
}
public void SetPosition(long position)
{
this._streamWriter.BaseStream.Position = position;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects)
}
// free unmanaged resources (unmanaged objects) and override finalizer
this._streamWriter?.Dispose();
// TODO: set large fields to null
this._streamWriter?.Dispose();
disposedValue = true;
}
}
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
// ~MiniExcelStreamWriter()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method

View File

@ -0,0 +1,41 @@
<Query Kind="Program">
<NuGetReference>MiniExcel</NuGetReference>
<Namespace>MiniExcelLibs</Namespace>
</Query>
void Main()
{
ConsoleApplication.Program.Main(null);
}
// You can define other methods, fields, classes and namespaces here
namespace ConsoleApplication
{
using System;
using System.IO;
using System.IO.Compression;
public class Program
{
public static void Main(string[] args)
{
var path = Path.GetTempPath() + Guid.NewGuid() + ".zip";
Console.WriteLine(path);
using (FileStream zipToOpen = new FileStream(path, FileMode.Create))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry = archive.CreateEntry("Readme.txt");
using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
{
writer.WriteLine("Information about this package.");
writer.Flush();
writer.BaseStream.Position=0;
writer.WriteLine("========================");
}
}
}
}
}
}

View File

@ -34,6 +34,26 @@ namespace MiniExcelLibs.Tests
this.output = output;
}
[Fact]
public void TestIssue_DataReaderSupportDimension()
{
{
DataTable table = new DataTable();
{
table.Columns.Add("id", typeof(int));
table.Columns.Add("name", typeof(string));
table.Rows.Add(1, "Jack");
table.Rows.Add(2, "Mike");
}
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
DataTableReader reader = table.CreateDataReader();
MiniExcel.SaveAs(path, reader);
var xml = Helpers.GetZipFileContent(path, "xl/worksheets/sheet1.xml");
Assert.Contains("<x:autoFilter ref=\"A1:B3\" />", xml);
Assert.Contains("<x:dimension ref=\"A1:B3\" />", xml);
}
}
/// <summary>
/// [ · Issue #413 · MiniExcel/MiniExcel]
/// (https://github.com/MiniExcel/MiniExcel/issues/413)