Common Lisp Streams of SBCL Output Files
I'm on SBCL on debian.
For some reason, if I use this:
(with-open-file (output (open #p"file.txt"
:direction :output
:if-exists :overwrite))
(format output "test")))
Where file.txt
is a simple text file.
I am getting the error
#<SB-SYS:FD-STREAM for "file /home/me/file.txt" {1004A90813}> is not
a character output stream.
Even using it :element-type 'character
doesn't save me. I was unable to get any output stream opened by any method. If I try to use write-bit
it says it is not a binary output stream. No other recording functions work, such as write-sequence
or write-line
. They all return this error. How to fix it?
source to share
I made the big moments bold. The problem is actually more complex than one might think:
Let's look at the shape.
First mistake: it is not indented correctly . Let's indent:
(with-open-file (output (open #p"file.txt"
:direction :output
:if-exists :overwrite))
(format output "test")))
We can now see more errors. Additional parentheses
(with-open-file (output (open #p"file.txt"
:direction :output
:if-exists :overwrite))
(format output "test"))) ; <- additional parenthesis
But more importantly:
(open #p"file.txt"
:direction :output
:if-exists :overwrite)
The above opens a file to write the output and returns a stream.
WITH-OPEN-FILE
also opens the file. So you are trying to open a TWICE file, first for writing ..
(with-open-file (output stream)
(format output "test")))
Above, the file opens for reading. You have opened the file twice: first for writing, then for reading.
You are now trying to write from FORMAT
to the input stream.
The slightly surprising part is this: both open
and WITH-OPEN-FILE
can accept a file stream as a file spec. If it receives a file stream as a file specification, then the associated path is used for the open operation.
So, as mentioned in another answer, this would be more correct:
(with-open-file (output #p"file.txt"
:direction :output
:if-exists :supersede)
(format output "Hello"))
SBCL error message :
#<SB-SYS:FD-STREAM for "file /home/me/file.txt" {1004A90813}>
is not a character output stream.
The point of the error message here does not mean that the stream is not a character stream. This is not an output stream. The stream is actually a stream of input . Thus, calling FORMAT
using a thread will not work. Let's have a statement written to test this:
CL-USER 18 > (with-open-file (output (open #p"/tmp/file.txt"
:direction :output
:if-does-not-exist :create
:if-exists :overwrite))
(assert (output-stream-p output) (output)
"The stream ~a is not an output stream!"
output)
(format output "test"))
Error: The stream #<STREAM::LATIN-1-FILE-STREAM /tmp/file.txt>
is not an output stream!
Your additional question : Why does the following form work?
(with-open-file (input (open #p"file.txt")) ...)
It just opens the TWICE file for reading.
source to share
Improper use with-open-file
.
(with-open-file (output #p"file.txt"
:direction :output
:if-exists :supersede)
(format output "Hello"))
source to share