Skip to content

Commit

Permalink
feat insert sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
izanhzh committed Aug 16, 2024
1 parent b20ed40 commit f28f818
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 21 deletions.
5 changes: 5 additions & 0 deletions src/MiniExcel/Csv/CsvWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ public void Insert()
SaveAs();
}

public void InsertSheet(bool overwriteSheet)
{
throw new NotImplementedException();
}

public async Task SaveAsAsync(CancellationToken cancellationToken = default(CancellationToken))
{
await Task.Run(() => SaveAs(), cancellationToken).ConfigureAwait(false);
Expand Down
1 change: 1 addition & 0 deletions src/MiniExcel/IExcelWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ internal interface IExcelWriter
void SaveAs();
Task SaveAsAsync(CancellationToken cancellationToken = default(CancellationToken));
void Insert();
void InsertSheet(bool overwriteSheet);
}
}
34 changes: 33 additions & 1 deletion src/MiniExcel/MiniExcel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ public static MiniExcelDataReader GetReader(this Stream stream, bool useHeaderRo
public static void Insert(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null)
{
if (Path.GetExtension(path).ToLowerInvariant() != ".csv")
throw new NotSupportedException("MiniExcel SaveAs only support csv insert now");
throw new NotSupportedException("MiniExcel only support csv insert now");

using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan))
Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration);
}

public static void Insert(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
{
if (excelType != ExcelType.CSV)
throw new NotSupportedException("MiniExcel only support csv insert now");

// reuse code
object v = null;
{
Expand All @@ -43,9 +46,38 @@ public static void Insert(this Stream stream, object value, string sheetName = "
else
v = value;
}
stream.Seek(0, SeekOrigin.End);
ExcelWriterFactory.GetProvider(stream, v, sheetName, excelType, configuration, false).Insert();
}

public static void InsertSheet(string path, object value, string sheetName, bool printHeader = true, ExcelType excelType = ExcelType.UNKNOWN, bool overwriteSheet = false)
{
if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
throw new NotSupportedException("MiniExcel SaveAs not support xlsm");

if (!File.Exists(path))
{
SaveAs(path, value, printHeader, sheetName, excelType);
}
else
{
using (var stream = new FileStream(path, FileMode.Open))
InsertSheet(stream, value, sheetName, printHeader, ExcelTypeHelper.GetExcelType(path, excelType), overwriteSheet);
}
}

public static void InsertSheet(this Stream stream, object value, string sheetName, bool printHeader = true, ExcelType excelType = ExcelType.XLSX, bool overwriteSheet = false)
{
var configuration = new OpenXmlConfiguration
{
FreezeRowCount = 0,
AutoFilter = false,
FastMode = true,
TableStyles = TableStyles.None
};
ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).InsertSheet(overwriteSheet);
}

public static void SaveAs(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false)
{
if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
Expand Down
115 changes: 95 additions & 20 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,69 @@ public ExcelOpenXmlSheetWriter()
{
}

public void InsertSheet(bool overwriteSheet)
{
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Styles)?.Delete();
GenerateStylesXml();//TODO: Style调整为非固定的,支持动态增加单元格样式,这样InsertSheet就不会覆盖掉其他Sheet的样式

var sheetRecords = new ExcelOpenXmlSheetReader(_stream, _configuration).GetWorkbookRels(_archive.Entries).ToArray();
foreach (var sheetRecord in sheetRecords.OrderBy(o => o.Id))
{
_sheets.Add(new SheetDto { Name = sheetRecord.Name, SheetIdx = (int)sheetRecord.Id, State = sheetRecord.State });
}
var existSheetDto = _sheets.SingleOrDefault(s => s.Name == _defaultSheetName);
if (existSheetDto == null)
{
currentSheetIndex = (int)sheetRecords.Max(m => m.Id) + 1;
var insertSheetInfo = GetSheetInfos(_defaultSheetName);
var insertSheetDto = insertSheetInfo.ToDto(currentSheetIndex);
_sheets.Add(insertSheetDto);
CreateSheetXml(_value, insertSheetDto.Path);
}
else if (overwriteSheet)
{
_archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete();
currentSheetIndex = existSheetDto.SheetIdx;
CreateSheetXml(_value, existSheetDto.Path);
}
else
{
throw new Exception($"Sheet “{_defaultSheetName}” already exist");
}

AddFilesToZip();

GenerateDrawinRelXml(currentSheetIndex);

GenerateDrawingXml(currentSheetIndex);

GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary<int, string> sheetsRelsXml);

foreach (var sheetRelsXml in sheetsRelsXml)
{
var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key);
_archive.Entries.SingleOrDefault(s => s.FullName == sheetRelsXmlPath)?.Delete();
CreateZipEntry(
sheetRelsXmlPath,
null,
ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value));
}

_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Workbook)?.Delete();
CreateZipEntry(
ExcelFileNames.Workbook,
ExcelContentTypes.Workbook,
ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString()));

_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete();
CreateZipEntry(
ExcelFileNames.WorkbookRels,
null,
ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()));

_archive.Dispose();
}

public void SaveAs()
{
GenerateDefaultOpenXml();
Expand Down Expand Up @@ -337,7 +400,7 @@ private void GenerateSheetByDataTable(MiniExcelStreamWriter writer, DataTable va
var prop = GetColumnInfosFromDynamicConfiguration(columnName);
props.Add(prop);
}

//sheet view
WriteSheetViews(writer);

Expand Down Expand Up @@ -398,7 +461,8 @@ private static void WriteColumnsWidths(MiniExcelStreamWriter writer, IEnumerable
writer.Write(WorksheetXml.EndCols);
}

private void WriteSheetViews(MiniExcelStreamWriter writer) {
private void WriteSheetViews(MiniExcelStreamWriter writer)
{
// exit early if no style to write
if (_configuration.FreezeRowCount <= 0 && _configuration.FreezeColumnCount <= 0)
{
Expand All @@ -417,7 +481,8 @@ private void WriteSheetViews(MiniExcelStreamWriter writer) {
writer.Write(WorksheetXml.EndSheetViews);
}

private void WritePanes(MiniExcelStreamWriter writer) {
private void WritePanes(MiniExcelStreamWriter writer)
{

string activePane;
if (_configuration.FreezeColumnCount > 0 && _configuration.FreezeRowCount > 0)
Expand All @@ -432,7 +497,7 @@ private void WritePanes(MiniExcelStreamWriter writer) {
{
activePane = "bottomLeft";
}
writer.Write( WorksheetXml.StartPane(
writer.Write(WorksheetXml.StartPane(
xSplit: _configuration.FreezeColumnCount > 0 ? _configuration.FreezeColumnCount : (int?)null,
ySplit: _configuration.FreezeRowCount > 0 ? _configuration.FreezeRowCount : (int?)null,
topLeftCell: ExcelOpenXmlUtils.ConvertXyToCell(
Expand All @@ -441,7 +506,7 @@ private void WritePanes(MiniExcelStreamWriter writer) {
),
activePane: activePane,
state: "frozen"
) );
));

// write pane selections
if (_configuration.FreezeColumnCount > 0 && _configuration.FreezeRowCount > 0)
Expand All @@ -452,16 +517,16 @@ private void WritePanes(MiniExcelStreamWriter writer) {
<selection pane="bottomLeft" activeCell="A3" sqref="A3"/>
<selection pane="bottomRight" activeCell="B3" sqref="B3"/>
*/
var cellTR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount+1, 1);
var cellTR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount + 1, 1);
writer.Write(WorksheetXml.PaneSelection("topRight", cellTR, cellTR));

var cellBL = ExcelOpenXmlUtils.ConvertXyToCell(1, _configuration.FreezeRowCount+1);
var cellBL = ExcelOpenXmlUtils.ConvertXyToCell(1, _configuration.FreezeRowCount + 1);
writer.Write(WorksheetXml.PaneSelection("bottomLeft", cellBL, cellBL));

var cellBR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount+1, _configuration.FreezeRowCount+1);
var cellBR = ExcelOpenXmlUtils.ConvertXyToCell(_configuration.FreezeColumnCount + 1, _configuration.FreezeRowCount + 1);
writer.Write(WorksheetXml.PaneSelection("bottomRight", cellBR, cellBR));
}
else if ( _configuration.FreezeColumnCount > 0 )
else if (_configuration.FreezeColumnCount > 0)
{
// freeze column
/*
Expand Down Expand Up @@ -610,27 +675,37 @@ private void GenerateDrawinRelXml()
{
for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++)
{
var drawing = GetDrawingRelationshipXml(sheetIndex);
CreateZipEntry(
ExcelFileNames.DrawingRels(sheetIndex),
null,
ExcelXml.DefaultDrawingXmlRels.Replace("{{format}}", drawing));
GenerateDrawinRelXml(sheetIndex);
}
}

private void GenerateDrawinRelXml(int sheetIndex)
{
var drawing = GetDrawingRelationshipXml(sheetIndex);
CreateZipEntry(
ExcelFileNames.DrawingRels(sheetIndex),
null,
ExcelXml.DefaultDrawingXmlRels.Replace("{{format}}", drawing));
}

private void GenerateDrawingXml()
{
for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++)
{
var drawing = GetDrawingXml(sheetIndex);

CreateZipEntry(
ExcelFileNames.Drawing(sheetIndex),
ExcelContentTypes.Drawing,
ExcelXml.DefaultDrawing.Replace("{{format}}", drawing));
GenerateDrawingXml(sheetIndex);
}
}

private void GenerateDrawingXml(int sheetIndex)
{
var drawing = GetDrawingXml(sheetIndex);

CreateZipEntry(
ExcelFileNames.Drawing(sheetIndex),
ExcelContentTypes.Drawing,
ExcelXml.DefaultDrawing.Replace("{{format}}", drawing));
}

/// <summary>
/// workbook.xml、workbookRelsXml
/// </summary>
Expand Down

0 comments on commit f28f818

Please sign in to comment.