-
Notifications
You must be signed in to change notification settings - Fork 2
/
file-write.scm
190 lines (158 loc) · 6.34 KB
/
file-write.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
;
; 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))
; --------------------------------------------------------
; 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!