525 lines
20 KiB
C#
525 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using gehGassi.Core.Interfaces;
|
|
|
|
namespace gehGassi.Core.Services
|
|
{
|
|
/// <summary>
|
|
/// Service der die Verwaltung von Dateien ermöglicht
|
|
/// </summary>
|
|
public class FileService : IFileService
|
|
{
|
|
private readonly string _root;
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="root">Root-Verzeichnis für alle Datei-Operationen</param>
|
|
[ExcludeFromCodeCoverage]
|
|
public FileService(string root)
|
|
{
|
|
_root = root;
|
|
if (!Directory.Exists(_root))
|
|
{
|
|
Directory.CreateDirectory(_root);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Erstellt einen Container, wenn nicht bereits vorhanden
|
|
/// </summary>
|
|
/// <param name="name">Name des Containers</param>
|
|
private void CreateContainerIfNotExists(string name)
|
|
{
|
|
var containerRoot = Path.Combine(_root, name);
|
|
if (!Directory.Exists(containerRoot))
|
|
{
|
|
Directory.CreateDirectory(containerRoot);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Speichern einer Datei in einen Container
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="filename">Dateiname (inkl. Pfad, wenn gewünscht)</param>
|
|
/// <param name="file">Datei als Byte-Array</param>
|
|
/// <param name="overwrite">Überschreiben vorhandener Daten</param>
|
|
public async Task<string> StoreAsync(string containerName, string filename, byte[] file, bool overwrite = true)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
|
|
filename = ToLocalFilename(filename);
|
|
|
|
var targetFile = Path.Combine(containerRoot, filename);
|
|
|
|
if (!overwrite)
|
|
{
|
|
if (File.Exists(targetFile))
|
|
throw new IOException("File already exists");
|
|
}
|
|
|
|
await File.WriteAllBytesAsync(targetFile, file);
|
|
return ToRelativeFilename(filename);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Speichern einer Datei in einen Container
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="filename">Dateiname (inkl. Pfad, wenn gewünscht)</param>
|
|
/// <param name="fileStream">Datei als Stream</param>
|
|
/// <param name="overwrite">Überschreiben vorhandener Daten</param>
|
|
public async Task<string> StoreAsync(string containerName, string filename, Stream fileStream, bool overwrite = true)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
|
|
filename = ToLocalFilename(filename);
|
|
|
|
var targetFile = Path.Combine(containerRoot, filename);
|
|
|
|
if (!overwrite)
|
|
{
|
|
if (File.Exists(targetFile))
|
|
throw new IOException("File already exists");
|
|
}
|
|
|
|
await using (var fs = new FileStream(targetFile, FileMode.Create, FileAccess.ReadWrite))
|
|
{
|
|
await fileStream.CopyToAsync(fs).ConfigureAwait(false);
|
|
}
|
|
return ToRelativeFilename(filename);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Umbenennen einer Datei in einem Container
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="filename">Dateiname (inkl. Pfad, wenn gewünscht)</param>
|
|
/// <param name="newFilename">Neuer Dateiname</param>
|
|
public async Task RenameAsync(string containerName, string filename, string newFilename)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
|
|
filename = ToLocalFilename(filename);
|
|
newFilename = ToLocalFilename(newFilename);
|
|
|
|
var sourceFileName = Path.Combine(containerRoot, filename);
|
|
var targetFileName = Path.Combine(containerRoot, newFilename);
|
|
|
|
File.Move(sourceFileName, targetFileName);
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Datei zurück
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="filename">Dateiname (inkl. Pfad, wenn gewünscht)</param>
|
|
/// <returns></returns>
|
|
public async Task<byte[]> GetAsync(string containerName, string filename)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
filename = ToLocalFilename(filename);
|
|
var targetFile = Path.Combine(containerRoot, filename);
|
|
|
|
if (File.Exists(targetFile))
|
|
{
|
|
return await File.ReadAllBytesAsync(targetFile);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Datei zurück
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="filename">Dateiname (inkl. Pfad, wenn gewünscht)</param>
|
|
/// <returns></returns>
|
|
public async Task<Stream> GetAsStreamAsync(string containerName, string filename)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
filename = ToLocalFilename(filename);
|
|
var targetFile = Path.Combine(containerRoot, filename);
|
|
|
|
if (File.Exists(targetFile))
|
|
{
|
|
await Task.CompletedTask;
|
|
return File.OpenRead(targetFile);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Löschen einer Datei in einem Container
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="filename">Dateiname (inkl. Pfad, wenn gewünscht)</param>
|
|
public async Task DeleteAsync(string containerName, string filename)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
filename = ToLocalFilename(filename);
|
|
var targetFile = Path.Combine(containerRoot, filename);
|
|
|
|
if (File.Exists(targetFile))
|
|
File.Delete(targetFile);
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Liste aller Dateien eines Containers zurück die sich in einem Directory befinden
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="directory">Verzeichnis.</param>
|
|
/// <param name="fileNamePart">Teil eines Dateinamens für die suche mit Wildcard!!!</param>
|
|
/// <returns>Liste von Dateien</returns>
|
|
public async Task<List<string>> ListFilesAsync(string containerName, string directory = "", string fileNamePart = "")
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var resultList = new List<string>();
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
directory = ToLocalDirectory(directory);
|
|
|
|
if (!string.IsNullOrWhiteSpace(fileNamePart))
|
|
directory += fileNamePart;
|
|
else
|
|
directory += "*";
|
|
|
|
var files = Directory.GetFiles(containerRoot, directory);
|
|
foreach (var file in files)
|
|
{
|
|
resultList.Add(ToRelativeFilename(file.Replace(containerRoot, "").Replace(@"\", "")));
|
|
}
|
|
await Task.CompletedTask;
|
|
return resultList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Liste aller Verzeichnise zurück die sich im Container befindne
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="root">wenn angegeben, wird von dem Verzeihnis als root ausgegangen</param>
|
|
/// <returns></returns>
|
|
public Task<List<string>> ListDirectoriesAsync(string containerName, string root = "")
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Koperien von Dateinen eines Containers in einen anderen
|
|
/// </summary>
|
|
/// <param name="sourceContainer">Quellcontainer</param>
|
|
/// <param name="sourceDirectory">Quellpfad</param>
|
|
/// <param name="targetContainer">ZielContainer</param>
|
|
/// <param name="targetDirectory">ZielPfad</param>
|
|
public async Task CopyFilesAsync(string sourceContainer, string sourceDirectory, string targetContainer, string targetDirectory)
|
|
{
|
|
CreateContainerIfNotExists(sourceContainer);
|
|
CreateContainerIfNotExists(targetContainer);
|
|
|
|
var source = Path.Combine(_root, sourceContainer);
|
|
sourceDirectory = ToLocalDirectory(sourceDirectory);
|
|
|
|
var target = Path.Combine(_root, targetContainer);
|
|
targetDirectory = ToLocalDirectory(targetDirectory);
|
|
|
|
var sourceFiles = Directory.GetFiles(source, sourceDirectory + "*");
|
|
foreach (var sourceFile in sourceFiles)
|
|
{
|
|
var fileName = GetFilename(sourceFile);
|
|
var targetFile = targetDirectory + fileName;
|
|
targetFile = Path.Combine(target, targetFile);
|
|
File.Copy(sourceFile, targetFile, true);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Koperien von Dateien eines Pfades in einen anderen
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="sourceDirectory">Quellpfad</param>
|
|
/// <param name="targetDirectory">ZielPfad</param>
|
|
public async Task CopyFilesAsync(string containerName, string sourceDirectory, string targetDirectory)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var source = Path.Combine(_root, containerName);
|
|
sourceDirectory = ToLocalDirectory(sourceDirectory);
|
|
|
|
var target = Path.Combine(_root, source);
|
|
targetDirectory = ToLocalDirectory(targetDirectory);
|
|
|
|
var sourceFiles = Directory.GetFiles(source, sourceDirectory + "*");
|
|
foreach (var sourceFile in sourceFiles)
|
|
{
|
|
var fileName = GetFilename(sourceFile);
|
|
var targetFile = targetDirectory + fileName;
|
|
targetFile = Path.Combine(target, targetFile);
|
|
File.Copy(sourceFile, targetFile, true);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verschieben von Dateien eines Containers in einen anderen
|
|
/// </summary>
|
|
/// <param name="sourceContainer">Quellcontainer</param>
|
|
/// <param name="sourceDirectory">Quellpfad</param>
|
|
/// <param name="targetContainer">ZielContainer</param>
|
|
/// <param name="targetDirectory">ZielPfad</param>
|
|
public async Task MoveFilesAsync(string sourceContainer, string sourceDirectory, string targetContainer, string targetDirectory)
|
|
{
|
|
CreateContainerIfNotExists(sourceContainer);
|
|
CreateContainerIfNotExists(targetContainer);
|
|
|
|
var source = Path.Combine(_root, sourceContainer);
|
|
sourceDirectory = ToLocalDirectory(sourceDirectory);
|
|
|
|
var target = Path.Combine(_root, targetContainer);
|
|
targetDirectory = ToLocalDirectory(targetDirectory);
|
|
|
|
var sourceFiles = Directory.GetFiles(source, sourceDirectory + "*");
|
|
foreach (var sourceFile in sourceFiles)
|
|
{
|
|
var fileName = GetFilename(sourceFile);
|
|
var targetFile = targetDirectory + fileName;
|
|
targetFile = Path.Combine(target, targetFile);
|
|
if (File.Exists(targetFile))
|
|
File.Delete(targetFile);
|
|
File.Move(sourceFile, targetFile);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verschieben von Dateien eines Pfades in einen anderen
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="sourceDirectory">Quellpfad</param>
|
|
/// <param name="targetDirectory">ZielPfad</param>
|
|
public async Task MoveFilesAsync(string containerName, string sourceDirectory, string targetDirectory)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var source = Path.Combine(_root, containerName);
|
|
sourceDirectory = ToLocalDirectory(sourceDirectory);
|
|
|
|
var target = Path.Combine(_root, source);
|
|
targetDirectory = ToLocalDirectory(targetDirectory);
|
|
|
|
var sourceFiles = Directory.GetFiles(source, sourceDirectory + "*");
|
|
foreach (var sourceFile in sourceFiles)
|
|
{
|
|
var fileName = GetFilename(sourceFile);
|
|
var targetFile = targetDirectory + fileName;
|
|
targetFile = Path.Combine(target, targetFile);
|
|
if (File.Exists(targetFile))
|
|
File.Delete(targetFile);
|
|
File.Move(sourceFile, targetFile);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Löschen des Inhalts eines Verzeichnises
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="directory">Verzeichnis</param>
|
|
/// <param name="fileNamePart">Optional: Dateinamen Wildcard mit *</param>
|
|
public async Task ClearDirectoryAsync(string containerName, string directory, string fileNamePart = "")
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
directory = ToLocalDirectory(directory);
|
|
|
|
if (!string.IsNullOrWhiteSpace(fileNamePart))
|
|
directory += fileNamePart;
|
|
else
|
|
directory += "*";
|
|
|
|
var files = Directory.GetFiles(containerRoot, directory);
|
|
foreach (var file in files)
|
|
{
|
|
File.Delete(file);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Löscht einen Container und den Inhalt
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
public async Task DeleteContainerAsync(string containerName)
|
|
{
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
if (Directory.Exists(containerRoot))
|
|
Directory.Delete(containerRoot, true);
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Löscht Dateien aus einem Ordner auf welche
|
|
/// vor dem Datum das letzte mal zugegriffen wurde
|
|
/// </summary>
|
|
/// <param name="containerName">Name des Containers</param>
|
|
/// <param name="directory">Verzeichnis</param>
|
|
/// <param name="date">Datum</param>
|
|
public async Task DeleteOldFilesAsync(string containerName, string directory, DateTimeOffset date)
|
|
{
|
|
CreateContainerIfNotExists(containerName);
|
|
|
|
var containerRoot = Path.Combine(_root, containerName);
|
|
directory = ToLocalDirectory(directory);
|
|
|
|
var files = Directory.GetFiles(containerRoot, directory + "*");
|
|
foreach (var file in files)
|
|
{
|
|
var info = new FileInfo(file);
|
|
if (info.LastAccessTimeUtc < date)
|
|
File.Delete(file);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt den reinen Dateinamen eines Files zurück (Ohne Directories usw)
|
|
/// </summary>
|
|
/// <param name="fileName">Dateiname</param>
|
|
/// <returns>Reiner Dateiname</returns>
|
|
public string GetFlatFilename(string fileName)
|
|
{
|
|
var file = ToLocalFilename(fileName);
|
|
file = GetFilename(file);
|
|
return file;
|
|
}
|
|
|
|
#region private
|
|
|
|
/// <summary>
|
|
/// Konvertiert einen Dateinamen mit Pfadangaben in einen Dateinamen
|
|
/// ohne Pfade. Diese sind nun in den Dateinamen integriert
|
|
/// </summary>
|
|
/// <param name="filename">Dateiname</param>
|
|
/// <returns>Dateiname</returns>
|
|
private string ToLocalFilename(string filename)
|
|
{
|
|
filename = filename.Replace(@"[", "");
|
|
filename = filename.Replace(@"]", "");
|
|
filename = filename.Replace(@"\", "[]");
|
|
filename = filename.Replace(@"/", "[]");
|
|
return filename;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Konvertiert ein Verzeichnis in die lokale Form
|
|
/// ohne Pfade. Diese sind nun in den Dateinamen integriert
|
|
/// </summary>
|
|
/// <param name="directory">Pfad</param>
|
|
/// <returns>Pfad</returns>
|
|
private string ToLocalDirectory(string directory)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(directory))
|
|
return "";
|
|
directory = directory.Replace(@"[", "");
|
|
directory = directory.Replace(@"]", "");
|
|
directory = directory.Replace(@"\", "[]");
|
|
directory = directory.Replace(@"/", "[]");
|
|
if (!directory.EndsWith("[]"))
|
|
directory += "[]";
|
|
return directory;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Konvertiert einen lokalen Dateinamen mit Pfadangaben
|
|
/// in einen relativen Pfad
|
|
/// </summary>
|
|
/// <param name="filename">Dateiname</param>
|
|
/// <returns>Dateiname</returns>
|
|
private string ToRelativeFilename(string filename)
|
|
{
|
|
filename = filename.Replace(@"[]", "/");
|
|
return filename;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Konvertiert einen lokalen Dateinamen mit Pfadangaben
|
|
/// in einen absoluten Pfad
|
|
/// </summary>
|
|
/// <param name="filename">Dateiname</param>
|
|
/// <returns>Dateiname</returns>
|
|
private string ToAbsoluteFilename(string filename)
|
|
{
|
|
filename = filename.Replace(@"[]", @"\");
|
|
return filename;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt den Dateinamen einer Datei ohne lokale Pfadangaben zurück
|
|
/// </summary>
|
|
/// <param name="path">Pfad + Dateinamen</param>
|
|
/// <returns>Dateiname ohne Pfadangaben</returns>
|
|
private string GetFilename(string path)
|
|
{
|
|
var fileName = path.Split(new[] { "[]" }, StringSplitOptions.None).Last();
|
|
return fileName;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hilfsklasse für das Finden von Dateien mittels Wildcards
|
|
/// </summary>
|
|
[ExcludeFromCodeCoverage]
|
|
internal class Wildcard : Regex
|
|
{
|
|
/// <summary>
|
|
/// Erstellt eine instanz
|
|
/// </summary>
|
|
/// <param name="pattern">Wildcard-Ausdruck</param>
|
|
public Wildcard(string pattern) : base(ToRegex(pattern))
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="pattern">Wildcard-Ausdruck</param>
|
|
/// <param name="options">Optionen</param>
|
|
public Wildcard(string pattern, RegexOptions options) : base(ToRegex(pattern), options)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Erstellt einen regulären Ausdruck aus dem Wildcard-Ausdruck
|
|
/// </summary>
|
|
/// <param name="pattern">Wildcard-Ausdruck</param>
|
|
/// <returns>Wildcard-Ausdruck in Regex konvertiert</returns>
|
|
public static string ToRegex(string pattern)
|
|
{
|
|
return "^" + Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$";
|
|
}
|
|
}
|
|
}
|