Created
June 26, 2023 23:38
-
-
Save DiracSpace/38944d70edcec41e5f05c903321f3d3f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Asterias.Application.Providers; | |
using Microsoft.AspNetCore.Http; | |
namespace Asterias.Infrastructure.Providers.File.LocalFileProvider | |
{ | |
public class LocalFileProvider : IFileProvider | |
{ | |
/// <summary> | |
/// Used for limiting amount of buffer | |
/// in memory | |
/// <see href="https://stackoverflow.com/questions/3033771/file-i-o-with-streams-best-memory-buffer-size">Best memory buffer size for streams</see> | |
/// </summary> | |
private const int BUFFER_SIZE = 0x4096; | |
/// <summary> | |
/// Create async resource for reading file | |
/// </summary> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
private FileStream OpenForReading(string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
return new FileStream( | |
path, | |
FileMode.Open, | |
FileAccess.Read, | |
FileShare.Read, | |
BUFFER_SIZE, | |
true | |
); | |
} | |
/// <summary> | |
/// Create async resource for writing/creating file | |
/// </summary> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
private FileStream OpenForWriting(string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
return new FileStream( | |
path, | |
FileMode.OpenOrCreate, | |
FileAccess.Write, | |
FileShare.None, | |
BUFFER_SIZE, | |
true | |
); | |
} | |
/// <summary> | |
/// Creates async resources for copying an existent | |
/// file from originPath to destinatioPath | |
/// </summary> | |
/// <param name="originPath"></param> | |
/// <param name="destinationPath"></param> | |
/// <returns></returns> | |
/// <exception cref="DirectoryNotFoundException"></exception> | |
/// <exception cref="UnauthorizedAccessException"></exception> | |
public async Task CopyAsync(string originPath, string destinationPath) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(originPath)); | |
ArgumentNullException.ThrowIfNull(nameof(destinationPath)); | |
using var originFileStream = OpenForReading(originPath); | |
using var destinationFileStream = OpenForWriting(destinationPath); | |
if (!originFileStream.CanRead) | |
throw new UnauthorizedAccessException(); | |
if (!destinationFileStream.CanWrite) | |
throw new UnauthorizedAccessException(); | |
await originFileStream.CopyToAsync(destinationFileStream); | |
} | |
/// <summary> | |
/// Copies an existing file to a new file, removing the | |
/// original file. | |
/// </summary> | |
/// <param name="originPath"></param> | |
/// <param name="destinationPath"></param> | |
/// <returns></returns> | |
public async Task MoveAsync(string originPath, string destinationPath) | |
{ | |
await CopyAsync(originPath, destinationPath); | |
Remove(originPath); | |
} | |
/// <summary> | |
/// Reads an entire file content as a byte array | |
/// </summary> | |
/// <param name="path">Full file path</param> | |
/// <returns></returns> | |
/// <exception cref="FileNotFoundException"></exception> | |
public async Task<byte[]> ReadAsync(string path) | |
{ | |
ArgumentNullException.ThrowIfNull(path, nameof(path)); | |
using var fileStream = OpenForReading(path); | |
byte[] buffer = new byte[fileStream.Length]; | |
await fileStream.ReadAsync( | |
buffer.AsMemory(0, (int)fileStream.Length) | |
); | |
return buffer; | |
} | |
/// <summary> | |
/// Opens an async resource for reading the contents of the file | |
/// into a string. | |
/// </summary> | |
/// <param name="path"></param> | |
/// <param name="encoding"></param> | |
/// <returns></returns> | |
/// <exception cref="FileNotFoundException"></exception> | |
/// <exception cref="ArgumentNullException"></exception> | |
public async Task<string> ReadAllTextAsync(string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
using var fileStream = new StreamReader(path); | |
string fileContents = await fileStream.ReadToEndAsync(); | |
return fileContents; | |
} | |
/// <summary> | |
/// Opens an async resource for reading line by line the contents | |
/// of the provided file. | |
/// </summary> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
/// <exception cref="FileNotFoundException"></exception> | |
public async Task<IEnumerable<string>> ReadAllLinesAsync(string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
var lines = new List<string>(); | |
using var streamReader = new StreamReader(path); | |
string? line = default; | |
while ((line = await streamReader.ReadLineAsync()) is not null) | |
lines.Add(line); | |
return lines; | |
} | |
/// <summary> | |
/// Tri | |
/// </summary> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
/// <exception cref="FileNotFoundException"></exception> | |
public void Remove(string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
System.IO.File.Delete(path); | |
} | |
/// <summary> | |
/// Opens an async resource for copying contents | |
/// of file. | |
/// </summary> | |
/// <param name="file"></param> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
/// <exception cref="ArgumentNullException"></exception> | |
/// <exception cref="UnauthorizedAccessException"></exception> | |
/// <exception cref="DirectoryNotFoundException"></exception> | |
public async Task SaveAsync(IFormFile file, string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(file)); | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
using var fileStream = OpenForWriting(path); | |
// TODO: this isn't working for now, but it's mentioned in file security | |
// should it be included too, or is this over complicating things? | |
// https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-7.0#validation | |
/*string fileName = System.IO.Path.GetFileName(path); | |
string fileExtension = System.IO.Path.GetExtension(fileName); | |
var signatureValidations = new FileSignatureValidations(); | |
if (!signatureValidations.IsSignatureValid(fileExtension, fileStream)) | |
throw new InvalidOperationException();*/ | |
if (!fileStream.CanWrite) | |
throw new UnauthorizedAccessException(); | |
await file.CopyToAsync(fileStream); | |
} | |
/// <summary> | |
/// Saves multiple files asynchronously | |
/// </summary> | |
/// <param name="files"></param> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
public async Task SaveAllAsync(IEnumerable<IFormFile> files, string path) | |
{ | |
foreach (var file in files) | |
await SaveAsync(file, path); | |
} | |
/// <summary> | |
/// Opens an async binary resource for writing the contents | |
/// of the binary array. | |
/// </summary> | |
/// <param name="content"></param> | |
/// <param name="path"></param> | |
/// <returns></returns> | |
/// <exception cref="ArgumentNullException"></exception> | |
/// <exception cref="UnauthorizedAccessException"></exception> | |
/// <exception cref="DirectoryNotFoundException"></exception> | |
public async Task SaveAllBytesAsync(byte[] content, string path) | |
{ | |
ArgumentNullException.ThrowIfNull(nameof(content)); | |
ArgumentNullException.ThrowIfNull(nameof(path)); | |
using var fileStream = OpenForWriting(path); | |
if (!fileStream.CanWrite) | |
throw new UnauthorizedAccessException(); | |
await fileStream.WriteAsync(content); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment