Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 45 additions & 37 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: MiniExcel Benchmarks

on:
workflow_dispatch:
release:
types: [published]

Expand Down Expand Up @@ -29,19 +30,14 @@ jobs:
env:
BenchmarkMode: Automatic
BenchmarkSection: query
- name: Commit report
working-directory: ./benchmarks
run: |
cp -r ./MiniExcel.Benchmarks/BenchmarkDotNet.Artifacts/results ./
git config user.name github-actions
git config user.email [email protected]
git pull
cd ./results
git add '*.md'
git commit -am "Automated benchmark report - query section"
git push --force
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Renaming result file
run: mv MiniExcelLibs.Benchmarks.XlsxBenchmark-report-github.md query-benchmark.md
working-directory: ./benchmarks/MiniExcel.Benchmarks/BenchMarkDotNet.Artifacts/results
- name: Save benchmark results
uses: actions/upload-artifact@v4
with:
name: query-benchmark-result
path: ./benchmark/MiniExcel.Benchmarks/BenchMarkDotNet.Artifacts/results/*.md

CreateBenchmark:
runs-on: ubuntu-latest
Expand All @@ -64,20 +60,15 @@ jobs:
env:
BenchmarkMode: Automatic
BenchmarkSection: create
- name: Commit report
working-directory: ./benchmarks
run: |
cp -r ./MiniExcel.Benchmarks/BenchmarkDotNet.Artifacts/results ./
git config user.name github-actions
git config user.email [email protected]
git pull
cd ./results
git add '*.md'
git commit -am "Automated benchmark report - create section"
git push --force
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Renaming result file
run: mv MiniExcelLibs.Benchmarks.XlsxBenchmark-report-github.md create-benchmark.md
working-directory: ./benchmarks/MiniExcel.Benchmarks/BenchMarkDotNet.Artifacts/results
- name: Save benchmark results
uses: actions/upload-artifact@v4
with:
name: create-benchmark-result
path: ./benchmark/MiniExcel.Benchmarks/BenchMarkDotNet.Artifacts/results/*.md

TemplateBenchmark:
runs-on: ubuntu-latest

Expand All @@ -99,16 +90,33 @@ jobs:
env:
BenchmarkMode: Automatic
BenchmarkSection: template
- name: Commit report
working-directory: ./benchmarks
- name: Renaming result file
run: mv MiniExcelLibs.Benchmarks.XlsxBenchmark-report-github.md template-benchmark.md
working-directory: ./benchmarks/MiniExcel.Benchmarks/BenchMarkDotNet.Artifacts/results
- name: Save benchmark results
uses: actions/upload-artifact@v4
with:
name: template-benchmark-result
path: ./benchmark/MiniExcel.Benchmarks/BenchMarkDotNet.Artifacts/results/*.md

PushBenchmarksResults:
runs-on: ubuntu-latest
needs: [ QueryBenchmark, CreateBenchmark, TemplateBenchmark ]

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch benchmark results
uses: actions/download-artifact@v4
with:
path: ./benchmarks/results
merge-multiple: true
- name: Commit reports
working-directory: ./benchmarks/results
run: |
cp -r ./MiniExcel.Benchmarks/BenchmarkDotNet.Artifacts/results ./
git config user.name github-actions
git config user.email [email protected]
git pull
cd ./results
git add '*.md'
git commit -am "Automated benchmark report - template section"
git push --force
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
git add ./*.md
git commit -am "Automated benchmark report - ${{ github.ref_name }}"
git push origin master --force-with-lease
4 changes: 2 additions & 2 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Setup .NET 8
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Restore dependencies
Expand Down
2 changes: 2 additions & 0 deletions MiniExcel.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs and setting", "Docs an
README.md = README.md
README.zh-CN.md = README.zh-CN.md
README.zh-Hant.md = README.zh-Hant.md
.github\workflows\benchmark.yml = .github\workflows\benchmark.yml
.github\workflows\codeql-analysis.yml = .github\workflows\codeql-analysis.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CC1E0601-AEC9-42D7-8F6A-3FB3939EED16}"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,7 @@ MiniExcel.AddPicture(path, images);
#### 7. Get Sheets Dimension

```csharp
var dim = MiniExcel.GetSheetsDimensions(path);
var dim = MiniExcel.GetSheetDimensions(path);
```

### Examples:
Expand Down
11 changes: 5 additions & 6 deletions benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
<PackageReference Include="ClosedXML" Version="0.102.3" />
<PackageReference Include="ClosedXML.Report" Version="0.2.11" />
<PackageReference Include="DocumentFormat.OpenXml" Version="2.20.0" />
<PackageReference Include="EPPlus" Version="7.7.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.15.0" />
<PackageReference Include="ClosedXML" Version="0.105.0" />
<PackageReference Include="ClosedXML.Report" Version="0.2.12" />
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="EPPlus" Version="7.7.2" />
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
<PackageReference Include="System.IO.Packaging" Version="9.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
16 changes: 11 additions & 5 deletions benchmarks/MiniExcel.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Running;
using MiniExcelLibs.Benchmarks;
using MiniExcelLibs.Benchmarks.BenchmarkSections;

Expand All @@ -11,12 +10,19 @@
"query" => typeof(QueryXlsxBenchmark),
"create" => typeof(CreateXlsxBenchmark),
"template" => typeof(TemplateXlsxBenchmark),
_ => throw new InvalidEnumArgumentException($"Benchmark section {section} does not exist")
_ => throw new ArgumentException($"Benchmark section {section} does not exist")
};

BenchmarkRunner.Run(benchmark, new Config(), args);
}
else
{
BenchmarkSwitcher
.FromTypes([typeof(CreateXlsxBenchmark)])
.Run(args, new Config());
.FromTypes(
[
typeof(QueryXlsxBenchmark),
typeof(CreateXlsxBenchmark),
typeof(TemplateXlsxBenchmark)
])
.Run(args, new Config());
}
9 changes: 5 additions & 4 deletions src/MiniExcel/Csv/CsvConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ namespace MiniExcelLibs.Csv
{
public class CsvConfiguration : Configuration
{
private static Encoding _defaultEncoding = new UTF8Encoding(true);
private static readonly Encoding DefaultEncoding = new UTF8Encoding(true);

public char Seperator { get; set; } = ',';
public string NewLine { get; set; } = "\r\n";
public bool ReadLineBreaksWithinQuotes { get; set; } = true;
public bool ReadEmptyStringAsNull { get; set; } = false;
public bool AlwaysQuote { get; set; } = false;
public bool QuoteWhitespaces { get; set; } = true;
public Func<string, string[]> SplitFn { get; set; }
public Func<Stream, StreamReader> StreamReaderFunc { get; set; } = (stream) => new StreamReader(stream, _defaultEncoding);
public Func<Stream, StreamWriter> StreamWriterFunc { get; set; } = (stream) => new StreamWriter(stream, _defaultEncoding);
public Func<Stream, StreamReader> StreamReaderFunc { get; set; } = (stream) => new StreamReader(stream, DefaultEncoding);
public Func<Stream, StreamWriter> StreamWriterFunc { get; set; } = (stream) => new StreamWriter(stream, DefaultEncoding);

internal readonly static CsvConfiguration DefaultConfiguration = new CsvConfiguration();
internal static readonly CsvConfiguration DefaultConfiguration = new CsvConfiguration();
}
}

20 changes: 9 additions & 11 deletions src/MiniExcel/Csv/CsvHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
internal static class CsvHelpers
{
/// <summary>If content contains special characters then use "{value}" format</summary>
public static string ConvertToCsvValue(string value, bool alwaysQuote, char separator)
public static string ConvertToCsvValue(string value, CsvConfiguration configuration)
{
if (value == null)
return string.Empty;
Expand All @@ -13,16 +13,14 @@ public static string ConvertToCsvValue(string value, bool alwaysQuote, char sepa
value = value.Replace("\"", "\"\"");
return $"\"{value}\"";
}

if (value.Contains(separator.ToString()) || value.Contains(" ") || value.Contains("\n") || value.Contains("\r"))
{
return $"\"{value}\"";
}

if (alwaysQuote)
return $"\"{value}\"";

return value;

var shouldQuote = configuration.AlwaysQuote ||
(configuration.QuoteWhitespaces && value.Contains(" ")) ||
value.Contains(configuration.Seperator.ToString()) ||
value.Contains("\r") ||
value.Contains("\n");

return shouldQuote ? $"\"{value}\"" : value;
}
}
}
4 changes: 2 additions & 2 deletions src/MiniExcel/Csv/CsvWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public int Insert(bool overwriteSheet = false)

private void AppendColumn(StringBuilder rowBuilder, CellWriteInfo column)
{
rowBuilder.Append(CsvHelpers.ConvertToCsvValue(ToCsvString(column.Value, column.Prop), _configuration.AlwaysQuote, _configuration.Seperator));
rowBuilder.Append(CsvHelpers.ConvertToCsvValue(ToCsvString(column.Value, column.Prop), _configuration));
rowBuilder.Append(_configuration.Seperator);
}

Expand All @@ -63,7 +63,7 @@ private static void RemoveTrailingSeparator(StringBuilder rowBuilder)

private string GetHeader(List<ExcelColumnInfo> props) => string.Join(
_configuration.Seperator.ToString(),
props.Select(s => CsvHelpers.ConvertToCsvValue(s?.ExcelColumnName, _configuration.AlwaysQuote, _configuration.Seperator)));
props.Select(s => CsvHelpers.ConvertToCsvValue(s?.ExcelColumnName, _configuration)));

private int WriteValues(object values)
{
Expand Down
26 changes: 17 additions & 9 deletions src/MiniExcel/OpenXml/SharedStringsDiskCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;

namespace MiniExcelLibs.OpenXml
Expand Down Expand Up @@ -37,9 +36,11 @@ internal void Add(int index, string value)
{
if (index > _maxIndx)
_maxIndx = index;
byte[] valueBs = _encoding.GetBytes(value);

var valueBs = _encoding.GetBytes(value);
if (value.Length > 32767) //check info length, becasue cell string max length is 47483647
throw new ArgumentOutOfRangeException("Excel one cell max length is 32,767 characters");
throw new ArgumentOutOfRangeException("", "Excel one cell max length is 32,767 characters");

_positionFs.Write(BitConverter.GetBytes(_valueFs.Position), 0, 4);
_lengthFs.Write(BitConverter.GetBytes(valueBs.Length), 0, 4);
_valueFs.Write(valueBs, 0, valueBs.Length);
Expand All @@ -49,16 +50,19 @@ private string GetValue(int index)
{
_positionFs.Position = index * 4;
var bytes = new byte[4];
_positionFs.Read(bytes, 0, 4);
_ = _positionFs.Read(bytes, 0, 4);
var position = BitConverter.ToInt32(bytes, 0);

bytes = new byte[4];
_lengthFs.Position = index * 4;
_lengthFs.Read(bytes, 0, 4);
_ = _lengthFs.Read(bytes, 0, 4);
var length = BitConverter.ToInt32(bytes, 0);
_valueFs.Position = position;

bytes = new byte[length];
_valueFs.Read(bytes, 0, length);
var v = _encoding.GetString(bytes);
return v;
_valueFs.Position = position;
_ = _valueFs.Read(bytes, 0, length);

return _encoding.GetString(bytes);
}

protected virtual void Dispose(bool disposing)
Expand All @@ -69,15 +73,19 @@ protected virtual void Dispose(bool disposing)
{
// TODO: dispose managed state (managed objects)
}

_positionFs.Dispose();
if (File.Exists(_positionFs.Name))
File.Delete(_positionFs.Name);

_lengthFs.Dispose();
if (File.Exists(_lengthFs.Name))
File.Delete(_lengthFs.Name);

_valueFs.Dispose();
if (File.Exists(_valueFs.Name))
File.Delete(_valueFs.Name);

_disposedValue = true;
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/MiniExcel/Utils/ExcelTypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ internal static ExcelType GetExcelType(Stream stream, ExcelType excelType)

var probe = new byte[8];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(probe, 0, probe.Length);
var read = stream.Read(probe, 0, probe.Length);
if (read != probe.Length)
throw new InvalidDataException("The file/stream does not contain enough data to process");

stream.Seek(0, SeekOrigin.Begin);

// New office format (can be any ZIP archive)
Expand All @@ -41,7 +44,7 @@ internal static ExcelType GetExcelType(Stream stream, ExcelType excelType)
return ExcelType.XLSX;
}

throw new NotSupportedException("Stream cannot know the file type, please specify ExcelType manually");
throw new InvalidDataException("The file type could not be inferred automatically, please specify ExcelType manually");
}
}
}
Loading
Loading