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
10 changes: 9 additions & 1 deletion src/MiniExcel.Core/OpenXml/OpenXmlConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,24 @@ public class OpenXmlConfiguration : MiniExcelBaseConfiguration
public int FreezeRowCount { get; set; } = 1;
public int FreezeColumnCount { get; set; } = 0;
public bool EnableConvertByteArray { get; set; } = true;
public bool EnableWriteFilePath{ get; set; } = true;
public bool IgnoreTemplateParameterMissing { get; set; } = true;
public bool EnableWriteNullValueCell { get; set; } = true;
public bool WriteEmptyStringAsNull { get; set; } = false;
public bool TrimColumnNames { get; set; } = true;
public bool IgnoreEmptyRows { get; set; } = false;

public bool EnableSharedStringCache { get; set; } = true;
public long SharedStringCacheSize { get; set; } = 5 * 1024 * 1024;

/// <summary>
/// The directory where the shared strings cache files are stored.
/// It defaults to the system's temporary folder.
/// </summary>
public string SharedStringCachePath { get; set; } = Path.GetTempPath();

public OpenXmlStyleOptions StyleOptions { get; set; } = new();
public DynamicExcelSheetAttribute[]? DynamicSheets { get; set; }
public bool EnableWriteFilePath{ get; set; } = true;

/// <summary>
/// Calculate column widths automatically from each column value.
Expand Down
2 changes: 1 addition & 1 deletion src/MiniExcel.Core/OpenXml/OpenXmlReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ private async Task SetSharedStringsAsync(CancellationToken cancellationToken = d
#endif
if (_config.EnableSharedStringCache && sharedStringsEntry.Length >= _config.SharedStringCacheSize)
{
SharedStrings = new SharedStringsDiskCache();
SharedStrings = new SharedStringsDiskCache(_config.SharedStringCachePath);
await foreach (var sharedString in XmlReaderHelper.GetSharedStringsAsync(stream, cancellationToken, Ns).ConfigureAwait(false))
{
SharedStrings[idx++] = sharedString;
Expand Down
34 changes: 18 additions & 16 deletions src/MiniExcel.Core/OpenXml/Utils/SharedStringsDiskCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,45 @@

internal class SharedStringsDiskCache : IDictionary<int, string>, IDisposable
{
private const int ExcelCellMaxLength = 32767;
private static readonly Encoding Encoding = new UTF8Encoding(true);

private readonly FileStream _positionFs;
private readonly FileStream _lengthFs;
private readonly FileStream _valueFs;

private long _maxIndx = -1;

private long _maxIndex = -1;
private bool _disposedValue;

public int Count => checked((int)(_maxIndx + 1));
public int Count => checked((int)(_maxIndex + 1));

public string this[int key]
{
get => GetValue(key);
set => Add(key, value);
}

public bool ContainsKey(int key) => key <= _maxIndx;
public bool ContainsKey(int key) => key <= _maxIndex;

public SharedStringsDiskCache()
public SharedStringsDiskCache(string sharedStringsCacheDir)
{
var path = $"{Guid.NewGuid().ToString()}_miniexcelcache";

_positionFs = new FileStream($"{path}_position", FileMode.OpenOrCreate);
_lengthFs = new FileStream($"{path}_length", FileMode.OpenOrCreate);
_valueFs = new FileStream($"{path}_data", FileMode.OpenOrCreate);
if (string.IsNullOrWhiteSpace(sharedStringsCacheDir) || !Directory.Exists(sharedStringsCacheDir))
throw new DirectoryNotFoundException($"\"{sharedStringsCacheDir}\" is not a valid directory for the shared strings cache.");

var prefix = $"{Path.GetRandomFileName()}_miniexcel";
_positionFs = new FileStream(Path.Combine(sharedStringsCacheDir, $"{prefix}_position"), FileMode.OpenOrCreate);
_lengthFs = new FileStream(Path.Combine(sharedStringsCacheDir, $"{prefix}_length"), FileMode.OpenOrCreate);
_valueFs = new FileStream(Path.Combine(sharedStringsCacheDir, $"{prefix}_data"), FileMode.OpenOrCreate);
}

// index must start with 0-N
internal void Add(int index, string value)
private void Add(int index, string value)
{
if (index > _maxIndx)
_maxIndx = index;
if (index > _maxIndex)
_maxIndex = index;

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

_positionFs.Write(BitConverter.GetBytes(_valueFs.Position), 0, 4);
Expand Down Expand Up @@ -105,13 +107,13 @@ public bool Remove(KeyValuePair<int, string> item)

public IEnumerator<KeyValuePair<int, string>> GetEnumerator()
{
for (int i = 0; i < _maxIndx; i++)
for (int i = 0; i <= _maxIndex; i++)
yield return new KeyValuePair<int, string>(i, this[i]);
}

IEnumerator IEnumerable.GetEnumerator()
{
for (int i = 0; i < _maxIndx; i++)
for (int i = 0; i <= _maxIndex; i++)
yield return this[i];
}

Expand Down
21 changes: 9 additions & 12 deletions tests/MiniExcel.Core.Tests/MiniExcelIssueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,22 +303,19 @@ public void TestIssue360()
[Fact]
public void TestIssue117()
{
var cacheFull = new SharedStringsDiskCache(Path.GetTempPath());
for (int i = 0; i < 100; i++)
{
var cache = new SharedStringsDiskCache();
for (int i = 0; i < 100; i++)
{
cache[i] = i.ToString();
}
for (int i = 0; i < 100; i++)
{
Assert.Equal(i.ToString(), cache[i]);
}
Assert.Equal(100, cache.Count);
cacheFull[i] = i.ToString();
}
for (int i = 0; i < 100; i++)
{
var cache = new SharedStringsDiskCache();
Assert.Empty(cache);
Assert.Equal(i.ToString(), cacheFull[i]);
}
Assert.Equal(100, cacheFull.Count);

var cacheEmpty = new SharedStringsDiskCache(Path.GetTempPath());
Assert.Empty(cacheEmpty);
}

[Fact]
Expand Down
Loading