| Arc has some nice primitives for reading and writing text files... so long as those files are Arc code. If you're just manipulating plain text or binary, then your options are rather more limited. So here are two operators that make it a bit nicer to work with any kind of file or port. First up is drainf, which works just like drain except that you can call any function on the stuff you're reading from a port (drain just dumps it all in a list). (mac drainf (expr f (o eof nil))
(w/uniq (gdone gres)
`(let ,gdone nil
(while (no ,gdone)
(let ,gres ,expr
(if (is ,gres ,eof)
(= ,gdone t)
(,f ,gres)))))))
What is drainf useful for? Well, for implementing things like this next function: pump takes two ports and pumps all the data from one port to another. (def pump (in out (o binary nil))
(with (err-flag t
inport (if (isa in 'string) (instring in) in)
outport (if (isa out 'string) (outstring out) out))
(after
(do
(if binary
(drainf (readb inport) [writeb _ outport])
(drainf (readc inport) [writec _ outport]))
(= err-flag nil)
(if (isa out 'string)
(inside outport)
out))
(if (isa in 'string) (close inport))
(if (isa out 'string) (close outport)))))
You can specify character (default) or binary ports. You can also pass strings instead of ports, in which case pump will pump data to/from your string. For example, to write a string out to a text file, do this: (w/outfile o "myfile" (pump "Some text" o))
or if you want to read a text file into a string, try this: (= text (w/infile i "myfile" (pump i "")))
or you can specify two file ports to copy the contents of one file to another, or two strings to copy the contents of one to another (????) or whatever. |