Writing Files in Racket

Here’s the translation of the Go code to Racket, with explanations in Markdown format suitable for Hugo:

Writing files in Racket follows similar patterns to the ones we saw earlier for reading.

#lang racket

(require racket/file)

(define (check e)
  (when e
    (error "An error occurred: ~a" e)))

;; To start, here's how to dump a string (or just bytes) into a file.
(define d1 #"hello\nracket\n")
(with-handlers ([exn:fail? (lambda (e) (check e))])
  (file->bytes "/tmp/dat1" d1))

;; For more granular writes, open a file for writing.
(define out (open-output-file "/tmp/dat2" #:exists 'replace))

;; It's idiomatic to use dynamic-wind to ensure file closure
(dynamic-wind
    (lambda () #f)  ; No setup needed
    (lambda ()
      ;; You can write byte strings as you'd expect.
      (define d2 #"some\n")
      (define n2 (write-bytes d2 out))
      (printf "wrote ~a bytes\n" n2)

      ;; A write-string is also available.
      (define n3 (write-string "writes\n" out))
      (printf "wrote ~a bytes\n" n3)

      ;; Use flush-output to ensure all buffered operations have
      ;; been applied to the underlying writer.
      (flush-output out)

      ;; Racket's port system provides buffering by default,
      ;; so there's no need for a separate buffered writer.
      (define n4 (write-string "buffered\n" out))
      (printf "wrote ~a bytes\n" n4))
    (lambda () (close-output-port out)))

Try running the file-writing code:

$ racket writing-files.rkt
wrote 5 bytes
wrote 7 bytes
wrote 9 bytes

Then check the contents of the written files:

$ cat /tmp/dat1
hello
racket

$ cat /tmp/dat2
some
writes
buffered

Next, we’ll look at applying some of the file I/O ideas we’ve just seen to the current-input-port and current-output-port streams.