320 lines
14 KiB
C#
320 lines
14 KiB
C#
|
|
namespace QWERTYkez.ExcelProcessor;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Статический класс для работы с документами Excel через процессоры чтения/записи.
|
|||
|
|
/// </summary>
|
|||
|
|
public static class ExcelProcessor
|
|||
|
|
{
|
|||
|
|
#region Read Operations
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ только для чтения и выполнить действия.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sourcePath">Путь к исходному файлу .xlsx</param>
|
|||
|
|
/// <param name="read">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryRead(string sourcePath, Action<IExcelReader> read)
|
|||
|
|
{
|
|||
|
|
return TryRead(new FileInfo(sourcePath), read);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ только для чтения и выполнить действия.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sourceFile">Объект <see cref="FileInfo"/> исходного файла .xlsx</param>
|
|||
|
|
/// <param name="read">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryRead(FileInfo sourceFile, Action<IExcelReader> read)
|
|||
|
|
{
|
|||
|
|
if (sourceFile is null || read is null)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine("[DEBUG] SourceFile or action is null");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
using var processor = ExcelReader.CreateInternal(sourceFile);
|
|||
|
|
if (processor is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
read(processor);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine($"[DEBUG] Error in read action: {ex.Message}");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Read Operations from Memory
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ из массива байт только для чтения и выполнить действия.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="data">Массив байт, содержащий документ .xlsx</param>
|
|||
|
|
/// <param name="read">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryRead(byte[] data, Action<IExcelReader> read)
|
|||
|
|
=> TryRead(new ReadOnlyMemory<byte>(data), read);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ из <see cref="ReadOnlyMemory{byte}"/> только для чтения и выполнить действия.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="data">Буфер с документом .xlsx</param>
|
|||
|
|
/// <param name="read">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryRead(ReadOnlyMemory<byte> data, Action<IExcelReader> read)
|
|||
|
|
{
|
|||
|
|
if (data.IsEmpty || read is null)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine("[DEBUG] Data is empty or action is null");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
using var processor = ExcelReader.CreateFromData(data);
|
|||
|
|
if (processor is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
read(processor);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine($"[DEBUG] Error in read action from memory: {ex.Message}");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Write Operations
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ для записи и выполнить действия с последующей перезаписью исходного файла.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sourcePath">Путь к исходному файлу .xlsx</param>
|
|||
|
|
/// <param name="write">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryWrite(string sourcePath, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
return TryWrite(sourcePath, sourcePath, write);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ для записи и выполнить действия с последующей перезаписью исходного файла.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sourceFile">Объект <see cref="FileInfo"/> исходного файла .xlsx</param>
|
|||
|
|
/// <param name="write">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryWrite(FileInfo sourceFile, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
return TryWrite(sourceFile, sourceFile.FullName, write);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ для записи, выполнить действия и сохранить результат по новому пути.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sourcePath">Путь к исходному файлу .xlsx</param>
|
|||
|
|
/// <param name="destinationPath">Путь для сохранения результата (null - перезапись исходного файла)</param>
|
|||
|
|
/// <param name="write">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryWrite(string sourcePath, string? destinationPath, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
return TryWrite(new FileInfo(sourcePath), destinationPath, write);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ для записи, выполнить действия и сохранить результат по новому пути.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sourceFile">Объект <see cref="FileInfo"/> исходного файла .xlsx</param>
|
|||
|
|
/// <param name="destinationPath">Путь для сохранения результата (null - перезапись исходного файла)</param>
|
|||
|
|
/// <param name="write">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryWrite(FileInfo sourceFile, string? destinationPath, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
if (sourceFile is null || write is null)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine("[DEBUG] SourceFile or action is null");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
using var processor = ExcelWriter.CreateInternal(sourceFile, destinationPath);
|
|||
|
|
if (processor is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
write(processor);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine($"[DEBUG] Error in write action: {ex.Message}");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region Write Operations from Memory
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ из массива байт для записи, выполнить действия и сохранить результат по указанному пути.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="data">Массив байт, содержащий документ .xlsx</param>
|
|||
|
|
/// <param name="destinationPath">Путь для сохранения результата</param>
|
|||
|
|
/// <param name="write">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryWrite(byte[] data, string destinationPath, Action<IExcelWriter> write)
|
|||
|
|
=> TryWrite(new ReadOnlyMemory<byte>(data), destinationPath, write);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается открыть документ из <see cref="ReadOnlyMemory{byte}"/> для записи, выполнить действия и сохранить результат по указанному пути.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="data">Буфер с документом .xlsx</param>
|
|||
|
|
/// <param name="destinationPath">Путь для сохранения результата</param>
|
|||
|
|
/// <param name="write">Действия для выполнения над документом</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/></returns>
|
|||
|
|
public static bool TryWrite(ReadOnlyMemory<byte> data, string destinationPath, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
if (data.IsEmpty || write is null)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine("[DEBUG] Data is empty or action is null");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
using var processor = ExcelWriter.CreateFromData(data, destinationPath);
|
|||
|
|
if (processor is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
write(processor);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
#if DEBUG
|
|||
|
|
Debug.WriteLine($"[DEBUG] Error in write action from memory: {ex.Message}");
|
|||
|
|
#endif
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается создать новый документ Excel, отредактировать его и вернуть результат в виде массива байт.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="result">Результирующий массив байт (если операция успешна).</param>
|
|||
|
|
/// <param name="write">Действия для заполнения документа.</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/>.</returns>
|
|||
|
|
public static bool TryCreate(out byte[] result, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
result = null!;
|
|||
|
|
if (write is null) return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using var writer = ExcelWriter.CreateNew();
|
|||
|
|
write(writer);
|
|||
|
|
result = writer.GetDocumentBytes(); // добавим этот метод в ExcelWriter
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается создать новый документ Excel, отредактировать его и записать в указанный поток.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="outputStream">Поток, в который будет записан документ.</param>
|
|||
|
|
/// <param name="write">Действия для заполнения документа.</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/>.</returns>
|
|||
|
|
public static bool TryCreate(Stream outputStream, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
if (write is null || outputStream is null) return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using var writer = ExcelWriter.CreateNew();
|
|||
|
|
write(writer);
|
|||
|
|
writer.SaveTo(outputStream);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается создать новый документ Excel, отредактировать его и сохранить на диск.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="destinationPath">Путь для сохранения результата.</param>
|
|||
|
|
/// <param name="write">Действия для заполнения документа.</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/>.</returns>
|
|||
|
|
public static bool TryCreate(string destinationPath, Action<IExcelWriter> write)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(destinationPath) || write is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using var writer = ExcelWriter.CreateNew(destinationPath);
|
|||
|
|
write(writer);
|
|||
|
|
writer.Save();
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Пытается создать новый документ Excel, отредактировать его и прочитать результат в памяти.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="write">Действия для заполнения документа.</param>
|
|||
|
|
/// <param name="read">Действия для чтения полученного документа.</param>
|
|||
|
|
/// <returns><see langword="true"/> если операция выполнена успешно, иначе <see langword="false"/>.</returns>
|
|||
|
|
public static bool TryRead(Action<IExcelWriter> write, Action<IExcelReader> read)
|
|||
|
|
{
|
|||
|
|
if (write is null || read is null)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using var writer = ExcelWriter.CreateNew();
|
|||
|
|
write(writer);
|
|||
|
|
using var reader = writer.ToReader();
|
|||
|
|
read(reader);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|