5

I am 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 plain text file.

I get the error

#<SB-SYS:FD-STREAM for "file /home/me/file.txt" {1004A90813}> is not
a character output stream.

Even using :element-type 'character doesn't save me. I haven't been able to get any output stream opened by any method. If I try to use write-bit it says that it isn't a binary output stream. No other write functions work either, such as write-sequence or write-line. They all return this error. How do I fix this?

2 Answers 2

13

I've made the important points bold. The problem is actually more tricky then one might think:

Let's look at the form.

First mistake: it's not indented correctly. Let's indent:

(with-open-file (output (open #p"file.txt"
                              :direction :output
                              :if-exists :overwrite))
  (format output "test")))

Now we can see more mistakes. An additional parentheses

(with-open-file (output (open #p"file.txt"
                              :direction :output
                              :if-exists :overwrite))
  (format output "test")))  ; <- additional parenthesis

But more important:

(open #p"file.txt"
      :direction :output
      :if-exists :overwrite)

Above opens a file for writing output and returns a stream.

WITH-OPEN-FILE does also open a file. So you try to open the file TWICE, first for writing..

(with-open-file (output stream)
  (format output "test")))

Above opens a file for reading. You have opened the file twice: first for writing, then for reading.

Now you try to write with FORMAT to an input stream.

The slightly surprising part is this: both open and with-open-file can take a file stream as a file spec. If it gets a file stream as a file spec, then the associated pathname 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 is not that the stream is not a character stream. It's not an output stream. The stream actually is a character input stream! Thus calling FORMAT using the stream won't work. Let's write an assert to verify 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 extra question: Why is the following form working?

(with-open-file (input (open #p"file.txt")) ...)

It just opens the file TWICE for reading.

Sign up to request clarification or add additional context in comments.

1 Comment

What a fantastic thoughtful answer thank you Rainer!
3

Your usage of with-open-file is incorrect.

(with-open-file (output #p"file.txt"
                 :direction :output
                 :if-exists :supersede)
  (format output "Hello"))

1 Comment

That is interesting, because (with-open-file (input (open #p"file.txt")) was working without a problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.