Otávio Décio
Otávio Décio

Reputation: 74290

Enumerating files in Akka.net

As an exercise to learn Akka, I am trying to write a simple solution for a seemingly simple problem - how to efficiently recursively list directories and files under a starting folder.

If I use Directory.GetDirectories, that will be a blocking call that will read all directories in memory. This works well but I think it defeats the purpose of using Akka.

Now if I use Directory.EnumerateDirectories, I can then call Tell to self for directories or call Tell on a File handler that will for example log the file.

My problem is that I have no way of knowing when the whole process is done, that is, when my directory traversal finished. The program just sits there, waiting for something to shut it down.

Am I looking at this problem the wrong way? What options do I have in Akka to solve this problem?

EDIT: Add actor code

public class DirectoryActor : UntypedActor
{
    private readonly IActorRef fileActor;

    private readonly string initialPath;

    public DirectoryActor(IActorRef fileActor, string initialPath)
    {
        this.fileActor = fileActor;
        this.initialPath = initialPath;
    }

    protected override void OnReceive(object message)
    {
        foreach (string dir in Directory.EnumerateDirectories(message.ToString()))
        {
            Self.Tell(dir);
            foreach (string file in Directory.EnumerateFiles(dir))
            {
                this.fileActor.Tell(file);
            }
        }
    }
}

Upvotes: 2

Views: 129

Answers (2)

Patrick Allwood
Patrick Allwood

Reputation: 1832

The following works on the same premise as profesor79's answer in that you need to have a signal to identify when the work is complete. Another way to do this would be to use the ReceiveTimeout feature, which fires a timeout message if no message has been received for a specific length of time.

public class DirectoryActor : UntypedActor
{
    private readonly IActorRef fileActor;

    private readonly string initialPath;

    public DirectoryActor(IActorRef fileActor, string initialPath)
    {
        this.fileActor = fileActor;
        this.initialPath = initialPath;

        this.Context.SetReceiveTimeout(Timespan.FromSeconds(2));
    }

    protected override void OnReceive(object message)
    {
        if (message is ReceiveTimeout) return; //No more directories left to enumerate

        foreach (string dir in Directory.EnumerateDirectories(message.ToString()))
        {
            Self.Tell(dir);
            foreach (string file in Directory.EnumerateFiles(dir))
            {
                this.fileActor.Tell(file);
            }
        }
    }
}

Upvotes: 1

profesor79
profesor79

Reputation: 9473

it looks like we need to specify an exit statement - then we can compare amout of received and scanned dirs - so we know when task is done.

protected override void OnReceive(object message)
    {             
        dirReceived++;
        foreach (string dir in Directory.EnumerateDirectories(message.ToString()))
        {
            Self.Tell(dir);
            dirSentCount++;
            foreach (string file in Directory.EnumerateFiles(dir))
            {
                this.fileActor.Tell(file);
            }
        }

        if (dirReceived == dirSentCount)
        {
            Console.WriteLine("Finished");
        }
        else
        {
            Console.Write(".");
        }
    }

Upvotes: 0

Related Questions