Files
DatabaseSnapshots/Services/OptimizedFileService.cs
GuilhermeStrice 1108bf3ef6 add project
2025-07-09 19:24:12 +01:00

172 lines
6.9 KiB
C#

using EasyCompressor;
using System.Security.Cryptography;
using System.Text;
namespace DatabaseSnapshotsService.Services
{
public class OptimizedFileService
{
private const int DefaultBufferSize = 64 * 1024; // 64KB buffer
private const int LargeFileThreshold = 100 * 1024 * 1024; // 100MB
private const int ParallelThreshold = 50 * 1024 * 1024; // 50MB
private readonly LZ4Compressor _lz4 = new LZ4Compressor();
/// <summary>
/// Streaming LZ4 compression using EasyCompressor.LZ4
/// </summary>
public async Task CompressFileStreamingAsync(string sourcePath, string destinationPath, int bufferSize = DefaultBufferSize)
{
try
{
using var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, FileOptions.Asynchronous);
using var destinationStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize, FileOptions.Asynchronous);
await Task.Run(() => _lz4.Compress(sourceStream, destinationStream));
}
catch (Exception ex)
{
throw new InvalidOperationException($"Streaming LZ4 compression failed: {ex.Message}", ex);
}
}
/// <summary>
/// Streaming LZ4 decompression using EasyCompressor.LZ4
/// </summary>
public async Task DecompressFileStreamingAsync(string sourcePath, string destinationPath, int bufferSize = DefaultBufferSize)
{
try
{
using var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, FileOptions.Asynchronous);
using var destinationStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize, FileOptions.Asynchronous);
await Task.Run(() => _lz4.Decompress(sourceStream, destinationStream));
}
catch (Exception ex)
{
throw new InvalidOperationException($"Streaming LZ4 decompression failed: {ex.Message}", ex);
}
}
/// <summary>
/// Optimized checksum calculation using streaming
/// </summary>
public async Task<string> CalculateChecksumStreamingAsync(string filePath, int bufferSize = DefaultBufferSize)
{
try
{
using var sha256 = SHA256.Create();
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, FileOptions.Asynchronous);
var buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
sha256.TransformBlock(buffer, 0, bytesRead, null, 0);
}
sha256.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
return Convert.ToBase64String(sha256.Hash!);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Checksum calculation failed: {ex.Message}", ex);
}
}
/// <summary>
/// Parallel checksum calculation for large files
/// </summary>
public async Task<string> CalculateChecksumParallelAsync(string filePath)
{
try
{
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length < LargeFileThreshold)
{
return await CalculateChecksumStreamingAsync(filePath);
}
// For large files, use parallel processing
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous);
var fileBytes = new byte[fileInfo.Length];
await stream.ReadAsync(fileBytes, 0, (int)fileInfo.Length);
return await Task.Run(() =>
{
using var sha256 = SHA256.Create();
return Convert.ToBase64String(sha256.ComputeHash(fileBytes));
});
}
catch (Exception ex)
{
throw new InvalidOperationException($"Parallel checksum calculation failed: {ex.Message}", ex);
}
}
/// <summary>
/// Optimized file reading with memory mapping for very large files
/// </summary>
public async Task<byte[]> ReadFileOptimizedAsync(string filePath)
{
try
{
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length > LargeFileThreshold)
{
// For very large files, use streaming
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous);
using var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
else
{
// For smaller files, use direct read
return await File.ReadAllBytesAsync(filePath);
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"File reading failed: {ex.Message}", ex);
}
}
/// <summary>
/// Optimized file writing with buffering
/// </summary>
public async Task WriteFileOptimizedAsync(string filePath, byte[] data, int bufferSize = DefaultBufferSize)
{
try
{
using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize, FileOptions.Asynchronous);
await stream.WriteAsync(data, 0, data.Length);
await stream.FlushAsync();
}
catch (Exception ex)
{
throw new InvalidOperationException($"File writing failed: {ex.Message}", ex);
}
}
/// <summary>
/// Get optimal buffer size based on file size
/// </summary>
public static int GetOptimalBufferSize(long fileSize)
{
if (fileSize < 1024 * 1024) // < 1MB
return 8 * 1024; // 8KB
else if (fileSize < 100 * 1024 * 1024) // < 100MB
return 64 * 1024; // 64KB
else
return 256 * 1024; // 256KB
}
/// <summary>
/// Determine if parallel processing should be used
/// </summary>
public static bool ShouldUseParallelProcessing(long fileSize)
{
return fileSize >= ParallelThreshold;
}
}
}