• Lexical
Show / Hide Table of Contents
  • Lexical.FileSystem
    • Introduction
    • Abstractions
      • IFileSystem
        • IFileSystem
        • IFileSystemBrowse
        • IFileSystemCreateDirectory
        • IFileSystemDelete
        • IFileSystemFileAttribute
        • IFileSystemMount
        • IFileSystemMove
        • IFileSystemObserve
        • IFileSystemOpen
      • IEvent
      • IEntry
      • IOption
      • IToken
    • FileSystem
    • VirtualFileSystem
    • MemoryFileSystem
    • EmbeddedFileSystem
    • HttpFileSystem
    • Decoration
    • IFileProvider
    • Utility
      • DisposeList
      • FileScanner
      • VisitTree
      • File Operation
  • Lexical.FileProvider
    • Introduction
    • Package
    • Package.Abstractions
    • Root
    • Zip
    • Dll
    • SharpCompress
    • SharpZipLib
    • FileScanner
    • Utils
  • Lexical.Localization
    • Introduction
    • Tutorial
    • Asset
      • IAsset
      • IStringAsset
    • Line
      • ILine
      • ILineFactory
      • ILineRoot
      • ILineFormat
      • ILineLogger
      • LineComparer
    • File
      • ILineReader
      • ILineWriter
      • Ini
      • Json
      • Xml
      • Resx
      • Resources
    • Miscellaneous
      • Plurality
      • ICulturePolicy
      • IStringFormat
      • Dependency Injection
    • Practices
      • Class Library
      • Class Library DI
      • Class Library DI opt.
  • Lexical.Utilities
    • Introduction
    • UnicodeString
    • FileScanner
    • Permutation
    • Tuples
    • StructList

Operation

The namespace Lexical.FileSystem.Operation contains file operation classes.

IOperation is ran inside a context of IOperationSession.

IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024*1024]);

using(var s = new OperationSession())
{
    new CopyFile(s, ms, "file", ms, "file.copy")
        .Estimate()
        .AssertCanRollback()
        .Run()
        .AssertSuccessful();
}
""
├── "file" [1048576]
└── "file.copy" [1048576]

IOperation.Estimate() makes checks to test if the operation can be completed. It throws exception if there is a visible reason why the operation would not complete.

var s = new OperationSession();
var op = new CopyFile(s, ms, "file", ms, "file.copy");
op.Estimate();

After .Estimate() is called, the property .CanRollback is set. It determines if the operation can be reverted.

Console.WriteLine(op.CanRollback);

.Estimate().AssertCanRollback() asserts rollback is possible.

op.Estimate().AssertCanRollback();

.Run() executes the operation. It throws an exception on unexpected error.

op.Run();

The caller should test the .CurrentState property after .Run() to see what the state is.

if (op.CurrentState == OperationState.Completed) 
    Console.WriteLine("ok");

... or use .Run().AssertSuccessful() to assert it.

op.Run().AssertSuccessful();

Caller can try rollback upon failure (or anyway).

try
{
    op.Run();
}
catch (Exception)
{
    // Rollback
    op.CreateRollback()?.Run();
}

Executing .Run(rollbackOnError) rollbacks automatically on failure if rollback is possible.

op.Run(rollbackOnError: true);

CopyTree copies a directory tree from one place to another.

IFileSystem ms = new MemoryFileSystem();
ms.CreateDirectory("dir/dir/dir/");
ms.CreateFile("dir/dir/dir/file", new byte[1024 * 1024]);

using (var s = new OperationSession())
{
    var op = new CopyTree(s, ms, "dir", ms, "dir.copy");

    op.Estimate().AssertCanRollback().Run().AssertSuccessful();
}
""
├── "dir"
│  └── "dir"
│     └── "dir"
│        └── "file"
└── "dir.copy"
   └── "dir"
      └── "dir"
         └── "file"

Batch is a list of operations to run as one operation.

IFileSystem ms = new MemoryFileSystem();                
using (var s = new OperationSession(policy: OperationPolicy.EstimateOnRun/*important*/))
{
    Batch batch = new Batch(s, OperationPolicy.Unset);

    batch.Ops.Add(new CreateDirectory(s, ms, "dir/dir/dir"));
    batch.Ops.Add(new CopyTree(s, ms, "dir", ms, "dir.copy"));
    batch.Ops.Add(new Delete(s, ms, "dir/dir", true, policy: OperationPolicy.EstimateOnRun));
    batch.Estimate().Run().AssertSuccessful();
}

TransferTree moves files from one location to another by copy-and-delete.

IFileSystem ms_src = new MemoryFileSystem();
ms_src.CreateDirectory("dir/dir/dir/");
ms_src.CreateFile("dir/dir/dir/file", new byte[1024 * 1024]);

IFileSystem ms_dst = new MemoryFileSystem();

using (var s = new OperationSession())
{
    var op = new TransferTree(s, ms_src, "dir", ms_dst, "dir.elsewhere");
    op.Estimate().AssertCanRollback().Run().AssertSuccessful();
}

Session gathers events automatically. Gathered evants can be read from the session object.

IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 1024]);

using (var s = new OperationSession())
{
    new CopyFile(s, ms, "file", ms, "file.copy")
        .Estimate()
        .AssertCanRollback()
        .Run()
        .AssertSuccessful();

    foreach (var @event in s.Events)
        Console.WriteLine(@event);
}
ms.PrintTo(Console.Out);
CopyFile(Src=file, Dst=file.copy, State=Completed) = Estimating
CopyFile(Src=file, Dst=file.copy, State=Completed) = Estimated
CopyFile(Src=file, Dst=file.copy, State=Completed) = Running
CopyFile(Src=file, Dst=file.copy, State=Completed) = Completed

Events can subscribed. Copy operation can be configured to send regular progress events. .SetProgressInterval(long) sets the interval on how often Operation.Event.Progress is sent in terms of bytes.

IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 20]);

using (var s = new OperationSession().SetProgressInterval(1024))
{
    s.Subscribe(new OpEventPrinter());

    new CopyFile(s, ms, "file", ms, "file.copy")
        .Estimate()
        .AssertCanRollback()
        .Run()
        .AssertSuccessful();
}
ms.PrintTo(Console.Out);
class OpEventPrinter : IObserver<IOperationEvent>
{
    public void OnCompleted() => Console.WriteLine("OnCompleted");
    public void OnError(Exception error) => Console.WriteLine(error);
    public void OnNext(IOperationEvent @event) => Console.WriteLine(@event);
}
CopyFile(Src=file, Dst=file.copy, State=Estimating) = Estimating
CopyFile(Src=file, Dst=file.copy, State=Estimated) = Estimated
CopyFile(Src=file, Dst=file.copy, State=Running) = Running
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 20%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 40%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 60%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 80%)
Progress(CopyFile(Src=file, Dst=file.copy, State=Running), 100%)
CopyFile(Src=file, Dst=file.copy, State=Completed) = Completed
OnCompleted
""
├── "file"
└── "file.copy"

If cancellation token is canceled, the operation does not proceed.

IFileSystem ms = new MemoryFileSystem();
ms.CreateFile("file", new byte[1024 * 10]);
CancellationTokenSource cancelSrc = new CancellationTokenSource();

using (var s = new OperationSession(cancelSrc: cancelSrc))
{
    cancelSrc.Cancel();
    new Move(s, ms, "file", ms, "file.moved")
        .Estimate()
        .AssertCanRollback()
        .Run()
        .AssertSuccessful();
}
Back to top Copyright © 2015-2020 Toni Kalajainen