Search code examples
factor-lang

How to Wait for more Content when Reading a File with Factor?


I have something like the following code

"file.txt" utf8 <file-reader> [ [ print ] each-line ] with-input-stream* ;

This works nicely for the current contents of file.txt and the processing (like printing in this case) ends when the end-of-file is reached. But I want the process to wait for new contents appended to the file and also process this. Or in other words, the current version implements Unix cat, but I want it to do tail -f.

I hoped with-input-stream* (mind the asterisk) would do the trick, as the docs say the stream is not closed at the end. But there must be something else I'm missing.


Solution

  • You're in luck, I wrote a utility like that a while ago. See https://github.com/bjourne/playground-factor/wiki/Tips-and-Tricks-Filesystem#tailing-a-file

    USING: accessors io io.encodings.utf8 io.files io.monitors kernel namespaces ;
    IN: examples.files.tail
    
    : emit-changes ( monitor -- )
        dup next-change drop
        input-stream get output-stream get stream-copy* flush
        emit-changes ;
    
    : seek-input-end ( -- )
        0 seek-end input-stream get stream>> stream-seek ;
    
    : tail-file ( fname -- )
        [
            dup f <monitor> swap utf8 [
                seek-input-end emit-changes
            ] with-file-reader
        ] with-monitors ;
    

    Your problem I think is that the quotation given to with-input-stream* will implicitly close the stream (each-line does it). I don't know if that is a bug or not. A word like this can be used to read the full stream without closing it:

    : my-stream-contents* ( stream -- seq )
        [ [ stream-read1 dup ] curry [ ] ] [ stream-exemplar produce-as nip ] bi ;
    

    Then:

    IN: scratchpad "/tmp/foo" utf8 <file-reader> [ my-stream-contents* print ] keep
    file contents here
    ...
    
    --- Data stack:
    T{ decoder f ~input-port~ utf8 f }
    IN: scratchpad my-stream-contents* print
    more file contents here
    ...