mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-29 18:38:08 +08:00
Fix dimension writing in FastMode (#659)
* Add tests for fast mode * Fix dimension writing in FastMode
This commit is contained in:
parent
6d81ddc59f
commit
29d4ee8af8
@ -8,10 +8,9 @@ namespace MiniExcelLibs.OpenXml.Constants
|
||||
internal const string StartWorksheetWithRelationship = @"<?xml version=""1.0"" encoding=""utf-8""?><x:worksheet xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships"" xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"" >";
|
||||
internal const string EndWorksheet = "</x:worksheet>";
|
||||
|
||||
internal const string StartDimension = @"<x:dimension ref=""";
|
||||
internal const string StartDimension = "<x:dimension ref=\"";
|
||||
internal const string DimensionPlaceholder = " />";
|
||||
internal static string Dimension(string dimensionRef)
|
||||
=> $"{StartDimension}{dimensionRef}\"/>";
|
||||
internal static string Dimension(string dimensionRef) => $"{StartDimension}{dimensionRef}\" />";
|
||||
|
||||
internal const string StartSheetViews = "<x:sheetViews>";
|
||||
internal const string EndSheetViews = "</x:sheetViews>";
|
||||
|
@ -77,9 +77,28 @@ namespace MiniExcelLibs.OpenXml
|
||||
await writer.WriteAsync(ExcelXml.EmptySheetXml);
|
||||
}
|
||||
|
||||
private async Task<long> WriteDimensionPlaceholderAsync(MiniExcelAsyncStreamWriter writer)
|
||||
{
|
||||
var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension);
|
||||
await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced
|
||||
|
||||
return dimensionPlaceholderPostition;
|
||||
}
|
||||
|
||||
private async Task WriteDimensionAsync(MiniExcelAsyncStreamWriter writer, int maxRowIndex, int maxColumnIndex, long placeholderPosition)
|
||||
{
|
||||
// Flush and save position so that we can get back again.
|
||||
var position = await writer.FlushAsync();
|
||||
|
||||
writer.SetPosition(placeholderPosition);
|
||||
await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
|
||||
|
||||
writer.SetPosition(position);
|
||||
}
|
||||
|
||||
private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter writer, IDataReader reader)
|
||||
{
|
||||
long dimensionWritePosition = 0;
|
||||
long dimensionPlaceholderPostition = 0;
|
||||
await writer.WriteAsync(WorksheetXml.StartWorksheet);
|
||||
var yIndex = 1;
|
||||
int maxColumnIndex;
|
||||
@ -87,8 +106,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
if (_configuration.FastMode)
|
||||
{
|
||||
dimensionWritePosition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension);
|
||||
await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced
|
||||
dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer);
|
||||
}
|
||||
|
||||
var props = new List<ExcelColumnInfo>();
|
||||
@ -139,8 +157,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
|
||||
if (_configuration.FastMode)
|
||||
{
|
||||
writer.SetPosition(dimensionWritePosition);
|
||||
await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
|
||||
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,14 +227,12 @@ namespace MiniExcelLibs.OpenXml
|
||||
|
||||
await writer.WriteAsync(WorksheetXml.StartWorksheetWithRelationship);
|
||||
|
||||
long dimensionWritePosition = 0;
|
||||
long dimensionPlaceholderPostition = 0;
|
||||
|
||||
// We can write the dimensions directly if the row count is known
|
||||
if (_configuration.FastMode && rowCount == null)
|
||||
{
|
||||
// Write a placeholder for the table dimensions and save thee position for later
|
||||
dimensionWritePosition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension);
|
||||
await writer.WriteAsync(WorksheetXml.DimensionPlaceholder);
|
||||
dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -269,9 +284,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
// The dimension has already been written if row count is defined
|
||||
if (_configuration.FastMode && rowCount == null)
|
||||
{
|
||||
// Seek back and write the dimensions of the table
|
||||
writer.SetPosition(dimensionWritePosition);
|
||||
await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
|
||||
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,19 +109,36 @@ namespace MiniExcelLibs.OpenXml
|
||||
writer.Write(ExcelXml.EmptySheetXml);
|
||||
}
|
||||
|
||||
private long WriteDimensionPlaceholder(MiniExcelStreamWriter writer)
|
||||
{
|
||||
var dimensionPlaceholderPostition = writer.WriteAndFlush(WorksheetXml.StartDimension);
|
||||
writer.Write(WorksheetXml.DimensionPlaceholder); // end of code will be replaced
|
||||
|
||||
return dimensionPlaceholderPostition;
|
||||
}
|
||||
|
||||
private void WriteDimension(MiniExcelStreamWriter writer, int maxRowIndex, int maxColumnIndex, long placeholderPosition)
|
||||
{
|
||||
// Flush and save position so that we can get back again.
|
||||
var position = writer.Flush();
|
||||
|
||||
writer.SetPosition(placeholderPosition);
|
||||
writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
|
||||
|
||||
writer.SetPosition(position);
|
||||
}
|
||||
|
||||
private void GenerateSheetByIDataReader(MiniExcelStreamWriter writer, IDataReader reader)
|
||||
{
|
||||
long dimensionWritePosition = 0;
|
||||
long dimensionPlaceholderPosition = 0;
|
||||
writer.Write(WorksheetXml.StartWorksheet);
|
||||
var yIndex = 1;
|
||||
int maxColumnIndex;
|
||||
int maxRowIndex;
|
||||
{
|
||||
|
||||
if (_configuration.FastMode)
|
||||
{
|
||||
dimensionWritePosition = writer.WriteAndFlush(WorksheetXml.StartDimension);
|
||||
writer.Write(WorksheetXml.DimensionPlaceholder); // end of code will be replaced
|
||||
dimensionPlaceholderPosition = WriteDimensionPlaceholder(writer);
|
||||
}
|
||||
|
||||
var props = new List<ExcelColumnInfo>();
|
||||
@ -177,8 +194,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
|
||||
if (_configuration.FastMode)
|
||||
{
|
||||
writer.SetPosition(dimensionWritePosition);
|
||||
writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
|
||||
WriteDimension(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,14 +264,12 @@ namespace MiniExcelLibs.OpenXml
|
||||
|
||||
writer.Write(WorksheetXml.StartWorksheetWithRelationship);
|
||||
|
||||
long dimensionWritePosition = 0;
|
||||
long dimensionPlaceholderPostition = 0;
|
||||
|
||||
// We can write the dimensions directly if the row count is known
|
||||
if (_configuration.FastMode && rowCount == null)
|
||||
{
|
||||
// Write a placeholder for the table dimensions and save thee position for later
|
||||
dimensionWritePosition = writer.WriteAndFlush(WorksheetXml.StartDimension);
|
||||
writer.Write(WorksheetXml.DimensionPlaceholder);
|
||||
dimensionPlaceholderPostition = WriteDimensionPlaceholder(writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -310,9 +324,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
// The dimension has already been written if row count is defined
|
||||
if (_configuration.FastMode && rowCount == null)
|
||||
{
|
||||
// Seek back and write the dimensions of the table
|
||||
writer.SetPosition(dimensionWritePosition);
|
||||
writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
|
||||
WriteDimension(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3734,5 +3734,82 @@ MyProperty4,MyProperty1,MyProperty5,MyProperty2,MyProperty6,,MyProperty3
|
||||
MiniExcel.SaveAs( path, values, excelType: ExcelType.XLSX, configuration: config, overwriteFile: true );
|
||||
|
||||
}
|
||||
|
||||
private class Issue658TestData
|
||||
{
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/mini-software/MiniExcel/issues/658
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Issue_658()
|
||||
{
|
||||
static IEnumerable<Issue658TestData> GetTestData()
|
||||
{
|
||||
yield return new() { FirstName = "Unit", LastName = "Test" };
|
||||
yield return new() { FirstName = "Unit1", LastName = "Test1" };
|
||||
yield return new() { FirstName = "Unit2", LastName = "Test2" };
|
||||
}
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
var testData = GetTestData();
|
||||
memoryStream.SaveAs(testData, configuration: new OpenXmlConfiguration
|
||||
{
|
||||
FastMode = true,
|
||||
});
|
||||
|
||||
memoryStream.Position = 0;
|
||||
|
||||
var queryData = memoryStream.Query<Issue658TestData>().ToList();
|
||||
|
||||
Assert.Equal(testData.Count(), queryData.Count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var data in testData)
|
||||
{
|
||||
Assert.Equal(data.FirstName, queryData[i].FirstName);
|
||||
Assert.Equal(data.LastName, queryData[i].LastName);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/mini-software/MiniExcel/issues/658
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Fact]
|
||||
public async Task Issue_658_async()
|
||||
{
|
||||
static IEnumerable<Issue658TestData> GetTestData()
|
||||
{
|
||||
yield return new() { FirstName = "Unit", LastName = "Test" };
|
||||
yield return new() { FirstName = "Unit1", LastName = "Test1" };
|
||||
yield return new() { FirstName = "Unit2", LastName = "Test2" };
|
||||
}
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
var testData = GetTestData();
|
||||
await memoryStream.SaveAsAsync(testData, configuration: new OpenXmlConfiguration
|
||||
{
|
||||
FastMode = true,
|
||||
});
|
||||
|
||||
memoryStream.Position = 0;
|
||||
|
||||
var queryData = (await memoryStream.QueryAsync<Issue658TestData>()).ToList();
|
||||
|
||||
Assert.Equal(testData.Count(), queryData.Count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var data in testData)
|
||||
{
|
||||
Assert.Equal(data.FirstName, queryData[i].FirstName);
|
||||
Assert.Equal(data.LastName, queryData[i].LastName);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user