OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-sensory / examples-v0 / file-write.scm

191 lines · scm ref:
;
; file-write.scm -- file-writing demo
;
; Demo of writing Atoms and Values to a text file. This includes
; streaming to a file.
;
(use-modules (opencog) (opencog exec) (opencog sensory-v0))

; --------------------------------------------------------
; Basic demo: Open a file for writing, and place some text into it.
; Open the file for writing; create it if it does not exist.
; Position cursor at the end of the file (for appending).
; The returned stream should be thought of as a cursor into the file.
(define txt-stream
	(cog-execute!
		(Open (Type 'TextFileStream) (Sensory "file:///tmp/foobar.txt"))))

; Perform `ls -la /tmp/foo*` and you should see a file of zero length.

; A WriteLink consists of two parts: where to write, and what
; to write. Since the write cursor is a Value, not an Atom, we
; cannot specify it directly. Thus, we place it at an anchor
; point. (Neither the name "file anchor", nor the key "output place"
; matter. They can be anything, and any atom can be used in their
; place, including Links.)
(cog-set-value!
	(Concept "file anchor") (Predicate "output place") txt-stream)

; Create a WriteLink
(define writer
	(WriteLink
		(ValueOf (Concept "file anchor") (Predicate "output place"))
		(Concept "stuff to write to the file\n")))

; Creating above does not write anything to the file.
; Verify this with another `ls -la /tmp/foo*`

; Write stuff to the file.
(cog-execute! writer)

; Verify that it was written: `cat /tmp/foobar.txt`
(cog-execute! writer)

; Do it a few more times.
(cog-execute! writer)
(cog-execute! writer)
(cog-execute! writer)

; --------------------------------------------------------
; Demo: Perform indirect streaming. The text to write will be placed as
; a StringValue at some location, and writing will be done from there.

(cog-set-value!
	(Concept "source") (Predicate "key")
	(StringValue
		"some text\n"
		"without a newline"
		"after it\n"
		"Goodbye!\n"))

; Redefine the writer.
(define writer
	(WriteLink
		(ValueOf (Concept "file anchor") (Predicate "output place"))
		(ValueOf (Concept "source") (Predicate "key"))))

; Write it out.
(cog-execute! writer)
(cog-execute! writer)
(cog-execute! writer)

; Verify that it was written: `cat /tmp/foobar.txt`

; --------------------------------------------------------
; Demo: Combine the reader and the writer to perform a file copy.
; Just as in the `file-read.scm` demo, the demo file should be copied
; to the temp directory, first: `cp demo.txt /tmp`

; Instead of using the custom scheme API `cog-set-value`, use the
; generic cog-execute! instead, and the SetValueLink to wire things
; into place.
(cog-execute!
	(SetValue
		(Concept "source") (Predicate "key")
		(Open (Type 'TextFileStream) (Sensory "file:///tmp/demo.txt"))))

; Running the writer will enter an infinite loop, pulling one line
; at a time from the input file, and writing it to the output file.
; The loop exits when end-of-file is reached.
(cog-execute! writer)

; Verify that it was written: `cat /tmp/foobar.txt`

; Try it again. Note that nothing will happen, because the input
; file iterator is now sitting at the end-of-file. Verify that there
; were no changes: `cat /tmp/foobar.txt`
(cog-execute! writer)

; Get a fresh handle to the input stream. Each call
; to SetValue will create a new file handle.
(cog-execute!
	(SetValue
		(Concept "source") (Predicate "key")
		(Open (Type 'TextFileStream) (Sensory "file:///tmp/demo.txt"))))

; And now write again:
(cog-execute! writer)

; Verify that a second copy was written: `cat /tmp/foobar.txt`

; --------------------------------------------------------
; Demo: Combine the reader and the writer to read, perform some
; processing, and then write the processed data out.

; Create a new file iterator for reading the demo text file.
(cog-execute!
	(SetValue
		(Concept "source") (Predicate "raw file input key")
		(Open (Type 'TextFileStream) (Sensory "file:///tmp/demo.txt"))))

; Define a rule that will take each line of input text, and
; process it in some way. In this case, it will just make
; two copies of each line. This is the same filter as in the
; `file-read.scm` demo. Review that demo if the below looks
; strange.
;
; Note that the `ValueOfLink` below behaves as a kind of promise:
; when executed, it promises to get the current value. In this case,
; it will be the next line of the input file.
(define rule-applier
	(Filter
		(Rule
			(TypedVariable (Variable "$x") (Type 'ItemNode))
			(Variable "$x")
			(LinkSignature
				(Type 'LinkValue)
				(Variable "$x")
				(Item "yo the first\n")
				(Variable "$x")
				(Item "yo the second\n")
				(Item "====\n")))
		(ValueOf (Concept "source") (Predicate "raw file input key"))))

; If we were to just `(cog-execute! rule-applier)`, we'd get exactly
; one line of the input file processed. This was already demoed in the
; `file-read.scm` demo. (If you're adventurous, you can try again here.
; Just remember to reset the input file iterator, when done.)
;
; We don't want to do just one line: we want to process the entire
; stream, until end-of-file. For that, create a promise to do that,
; when executed.
(define prom
	(Promise (TypeNode 'FutureStream)  rule-applier))

; Designate the promise as the source of data for the file writer.
(cog-execute!
	(SetValue (Concept "source") (Predicate "key") prom))

; Run the file-writer. This uses exactly the same definition as before.
; Be sure to `ls -la /tmp/foobar.txt` before and after running this,
; or just `cat` it, to see the output file contents change.
(cog-execute! writer)

; Do it again. Nothing happens, because the input file cursor is at
; the end of file.
(cog-execute! writer)

; Reset the input file cursor. (or pick a new input file.)
(cog-execute!
	(SetValue
		(Concept "source") (Predicate "raw file input key")
		(Open (Type 'TextFileStream) (Sensory "file:///tmp/demo.txt"))))

; Now, the writer will run again.
(cog-execute! writer)

; If unclear about the promise, you can explore it several ways.
; One is to do this: (Be sure to reset the input file, first.)
;    (cog-value->list (cog-execute! prom))
; This will process one line at a time.
;
; Equivalently, use ValueOf to get the value:
;    (cog-value->list (cog-execute!
;        (ValueOf (Concept "source") (Predicate "key"))))
;
; The writer just invokes this second form in an infinite loop,
; until the end-of-file is reached, and then it halts.

; --------------------------------------------------------
; The End! That's All, Folks!