How to use multiple file ports

I am trying to open 1 file for reading and another for writing, and ensure that if something goes wrong I always try to close the input and output ports. I thought there would be a compact structure for this but the code I came up with seems quite verbose:

(define (write-sections-to-file section-table filepath)
  (let ([out-filepath  (string-append filepath ".2")]
        [in-port       undefined]
        [out-port      undefined])
    (dynamic-wind
      (lambda () #f)
      (lambda ()
        (set! in-port   (open-input-file filepath #:mode 'text))
        (set! out-port  (open-output-file out-filepath #:mode 'text #:exists 'truncate))
        ; Do some stuff
        )
      (lambda ()
        (when (some? out-port)
          (close-output-port out-port))
        (when (some? in-port)
          (close-input-port in-port))))))

Is there a more idiomatic way to write this to get rid of (set!) and (dynamic-wind)?

call-with-input-file* and call-with-output-file* are your friends.

A convenient wrapper that opens two files using them:

(define (call-with-input/output-files* infile-name outfile-name proc
                                       #:input-mode [input-mode 'binary]
                                       #:output-mode [output-mode 'binary]
                                       #:exists [exists 'error]
                                       #:permissions [permissions #o666]
                                       #:replace-permissions? [replace-permissions? #f])
  (call-with-input-file* infile-name #:mode input-mode
    (lambda (infile)
      (call-with-output-file* outfile-name #:mode output-mode #:exists exists #:permissions permissions #:replace-permissions? replace-permissions?
                              (lambda (outfile) (proc infile outfile))))))



;;; (call-with-input/output-files* "in.txt" "out.txt"
;;;   (lambda (in out) (write-string (read-line in) out)))
2 Likes

Thanks @shawnw. I was hoping there is already something like this built into racket or the standard library. I can roll my own but wanted to check if this problem has already been solved and I just don't know about it :slight_smile: