简体   繁体   中英

Akka.Net file IO - process only the first n bytes of a file

I have this very simple stream to process a file - just a FileIO.FromFile source, a pass-through flow, and a Last sink:

    var source = FileIO.FromFile(new FileInfo(fileName));

    var flow = Flow.FromFunction<ByteString, ByteString>(x =>
    {
       Log.Info(x.Count.ToString());
       return x;
    });

    var sink = Sink.Last<ByteString>();

    var runnable = source.Via(flow).ToMaterialized(sink, Keep.Right);
    var result = runnable.Run(Context.Materializer()).Result;

The stream runs as expected: the logger spams out the bytestring sizes until the file source is completely exhausted.

Now, I change the sink to use First instead of Last

    var source = FileIO.FromFile(new FileInfo(fileName));

    var flow = Flow.FromFunction<ByteString, ByteString>(x =>
    {
       Log.Info(x.Count.ToString());
       return x;
    });

    var sink = Sink.First<ByteString>();

    var runnable = source.Via(flow).ToMaterialized(sink, Keep.Right);
    var result = runnable.Run(Context.Materializer()).Result;

The documentation for "First" states "cancels after receiving one element", which I assumed meant the sink signals a cancel up the stream, which would close the source. But when this stream is run, two things happen.

1) I get the following debug log message

[DEBUG][17/05/2018 13:55:16][Thread 0004][akka://Demo/user/DATReader/StreamSupervisor-0/Flow-0-1-fileSource] Unhandled message from akka://Demo/user/DATReader/StreamSupervisor-0/Flow-0-0-unknown-operation : Akka.Streams.Actors.Cancel

and

2) The file is locked, so any further attempt to read it fails with an access denied exception.

I also tried using Take(1) on the source, but the same effect is seen.

My question is: how do I read only the first n bytes from a file and shut down the stream gracefully so that any lock (obtained by FileIO.FromFile) is released?

In my case, there is no such error. Try using sharedKillSwitch to control completion. Documentation is here about Dynamic stream handling

            var sharedKillSwitch = KillSwitches.Shared("my-kill-switch");
            var source = FileIO.FromFile(new FileInfo(fileName), chunkSize: 1024)
                    .Via(sharedKillSwitch.Flow<ByteString>());

            var sink = Sink.First<ByteString>();

            var runnable = source.Select(x => {                 
                Log.Info(x.Count.ToString());
                sharedKillSwitch.Shutdown();
                return x;
            })
            .ToMaterialized(sink, Keep.Right);

            var result = runnable.Run(materializer).Result;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM