using System;
using System.Diagnostics.Contracts;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
namespace Cyrons
{
/// <summary>
/// Bietet Funktionalität für das einfache Laden und Speichern
/// von beliebigen Daten in komprimierter, binärer Form.
/// </summary>
/// <example>
/// <code>
/// <![CDATA[
///using System;
///
///namespace CompressorDemo
///{
/// [Serializable]
/// public class DemoDTO
/// {
/// // Ein paar Demodaten mit verchiedenen Typen.
/// public Guid ID { get; set; }
/// public string Vorname { get; set; }
/// public string Nachname { get; set; }
/// public DateTime Geburtstag { get; set; }
/// }
///}
///
/// ]]>
/// </code>
/// </example>
/// /// <example>
/// <code>
/// <![CDATA[
///using System;
///using System.IO;
///using Cyrons;
///
///namespace CompressorDemo
///{
/// internal class Program
/// {
/// static void Main()
/// {
/// string fullFilename = GetProjectPath(EnvironmentMode.Regular) + @"\Demodaten.bin";
///
/// // Der Backslash wird automatisch eingesetzt.
/// var compressor =
/// new CompressedBinaryFileIO(GetProjectPath(EnvironmentMode.Regular), "Demodaten", "bin");
///
/// //======================================================================
///
/// SaveDemo(compressor);
///
/// //======================================================================
///
/// Console.WriteLine("Now trying to load and decompress...");
/// LoadDemo(compressor, fullFilename);
///
/// //======================================================================
///
/// // Verhindert das selbsttätige Schließen des Konsolenfensters.
/// Console.WriteLine("\nPress any key to terminate the program.");
/// Console.ReadKey();
/// }
///
/// private static void LoadDemo(CompressedBinaryFileIO compressor, string fullFilename)
/// {
/// if(File.Exists(fullFilename))
/// {
/// try
/// {
/// DemoDTO oldData = compressor.Load() as DemoDTO;
///
/// if(oldData == null)
/// Console.WriteLine("Keine Daten zur Verarbeitung vorhanden.");
/// else
/// {
/// Console.WriteLine("ID: {0}", oldData.ID);
/// Console.WriteLine("Vorname: {0}", oldData.Vorname);
/// Console.WriteLine("Nachname: {0}", oldData.Nachname);
/// Console.WriteLine("Geburtstag: {0}", oldData.Geburtstag);
/// }
/// }
/// catch(Exception problem)
/// {
/// Console.WriteLine(problem);
/// }
/// }
/// else
/// Console.WriteLine("Das File existiert nicht.");
/// }
///
/// private static void SaveDemo(CompressedBinaryFileIO compressor)
/// {
/// var data = new DemoDTO
/// {
/// ID = Guid.NewGuid(),
/// Geburtstag = new DateTime(2009, 7, 5),
/// Nachname = "Demonachname",
/// Vorname = "Demovorname"
/// };
/// try
/// {
/// compressor.Save(data);
/// Console.WriteLine("File has successfully been saved." + Environment.NewLine);
/// }
/// catch(Exception problem)
/// {
/// Console.WriteLine(problem);
/// }
/// finally
/// {
/// data = null;
/// }
/// }
///
/// #region DemoHelper
///
/// /// <summary>
/// /// Holt den Pfad zum aktuellen Projekt-Ordner.
/// /// Dieses Property bitte nicht im Produktivcode benutzen.
/// /// </summary>
/// /// <returns>der Pfad zum aktuellen Projekt-Ordner.</returns>
/// private static string GetProjectPath(EnvironmentMode mode)
/// {
/// // Ergebnis: Debug- oder Release-Ordner im Projektordner.
/// string projectPath = Environment.CurrentDirectory;
/// // Mit jedem Durchlauf geht es im Verzeichnisbaum eine Stufe höher.
/// for(int i = 0; i < (int)mode; i++)
/// {
/// projectPath = Path.GetDirectoryName(projectPath);
/// }
/// return projectPath;
/// }
///
/// /// <summary>
/// /// Je nach Umgebung variiert die Anzahl der Stufen,
/// /// die in der Ordnerstruktur nach oben geklettert werden muß.
/// /// </summary>
/// private enum EnvironmentMode
/// {
/// /// <summary>
/// /// Klettert in der Ordnerstruktur 2 Stufen nach oben.
/// /// </summary>
/// Regular = 2,
///
/// /// <summary>
/// /// Klettert in der Ordnerstruktur 3 Stufen nach oben.
/// /// </summary>
/// UnitTests = 3
/// }
///
/// #endregion
/// }
///}
///
/// ]]>
/// </code>
/// </example>
public class CompressedBinaryFileIO
{
/// <summary>
/// Initialisiert eine neue Instanz der <see cref="CompressedBinaryFileIO"/> Klasse.
/// </summary>
/// <param name="path">Der Dateipfad,
/// in dem die Datei gespeichert oder geladen werden soll
/// (kein \ am Ende angeben).</param>
/// <param name="filename">Dateiname ohne Extension</param>
/// <param name="extension">Die Datei-Extension ohne vorangestellten Punkt.</param>
public CompressedBinaryFileIO(string path, string filename, string extension)
{
Contract.Requires(!string.IsNullOrEmpty(path));
Contract.Requires(!string.IsNullOrEmpty(filename));
Contract.Requires(!string.IsNullOrEmpty(extension));
Path = path;
Filename = filename;
Extension = extension;
fullFilename = Path + @"\" + Filename + "." + Extension;
}
private static readonly Object syncLock = new Object();
private readonly string fullFilename;
/// <summary>
/// Gibt den Pfad zurück, der im Konstruktor angegeben wurde.
/// </summary>
/// <value>The path.</value>
public string Path { get; private set; }
/// <summary>
/// Gibt den Dateinamen zurück, der im Konstruktor angegeben wurde.
/// </summary>
/// <value>The filename.</value>
public string Filename { get; private set; }
/// <summary>
/// Gibt die Datei-Extension zurück, der im Konstruktor angegeben wurde.
/// </summary>
/// <value>The extension.</value>
public string Extension { get; private set; }
/// <summary>
/// Lädt eine komprimierte Datei, die im Konstruktor definiert wurde.
/// Diese Methode ist threadsicher.
/// </summary>
/// <exception cref="Exception">Wirft Exceptions.</exception>
public object Load()
{
lock(syncLock)
{
var filePermissions = new FileIOPermission(
FileIOPermissionAccess.Read, fullFilename);
filePermissions.Assert();
var decompressedStream = new GZipStream(
File.OpenRead(fullFilename), CompressionMode.Decompress);
var formatter = new BinaryFormatter();
object data = formatter.Deserialize(decompressedStream);
decompressedStream.Close();
decompressedStream.Dispose();
formatter = null;
return data;
}
}
/// <summary>
/// Speichert eine komprimierte Datei, die im Konstruktor definiert wurde.
/// Im Falle daß die übergebenen Daten null, bricht die Methode ab.
/// Diese Methode ist threadsicher.
/// </summary>
/// <returns>true wenn die Daten erfolgreich gespeichert wurden, anderenfalls false.</returns>
/// <exception cref="Exception">Wirft Exceptions.</exception>
public bool Save(object data)
{
lock(syncLock)
{
if(data == null)
return false;
var filePermissions = new FileIOPermission(
FileIOPermissionAccess.Write, fullFilename);
filePermissions.Assert();
var compressedStream = new GZipStream(
File.Create(fullFilename), CompressionMode.Compress);
var formatter = new BinaryFormatter();
formatter.Serialize(compressedStream, data);
compressedStream.Close();
compressedStream.Dispose();
formatter = null;
return true;
}
}
}
}