JSRUN 用代码说话

输入/输出

编辑教程

输入/输出

通过前面章节的学习,你已经可以在Scheme的交互式前端中编写并执行程序了。在本章中,我讲介绍如何输入和输出。使用这个特性,你可以从文件中读取数据或向文件中写入数据。

从文件输入

open-input-file,read-char和eof-object?

函数(open-input-file filename)可以用于打开一个文件。此函数返回一个用于输入的端口。

函数(read-char port)用于从端口中读取一个字符。当读取到文件结尾(EOF)时,此函数返回eof-object,你可以使用eof-object?来检查。

函数(close-input-port port)用于关闭输入端口。[代码片段1]展示了一个函数,该函数以字符串形式返回了文件内容。

(define (read-file file-name)
  (let ((p (open-input-file file-name)))
    (let loop((ls1 '()) (c (read-char p)))
      (if (eof-object? c)
      (begin
        (close-input-port p)
        (list->string (reverse ls1)))
      (loop (cons c ls1) (read-char p))))))

比如,在[范例1]中展示的结果就是将[代码片段1]应用于文件hello.txt。由于换行符是由'\n'表示的,这就很容易阅读。然而,像格式化输出[范例2],我们也可使用display函数。


Hello world!
Scheme is an elegant programming language.
[范例1]

(cd "C:\\doc")
(read-file "hello.txt")
;Value 14: "Hello world!\nScheme is an elegant programming language.\n"
[范例2]

(display (read-file "hello.txt"))
Hello world!
Scheme is an elegant programming language.
;Unspecified return value

语法call-with-input-file和with-input-from-file

你通过使用语法call-with-input-file和with-input-from-file来打开文件以供读取输入。这些语法是非常方便的,因为它们要处理错误。

(call-with-input-file filename procedure)

该函数将名为filename的文件打开以供读取输入。函数procedure接受一个输入端口作为参数。文件有可能再次使用,因此当procedure结束时文件不会自动关闭,文件应该显式地关闭。[代码片段1]可以按照[代码片段2]那样用call-with-input-file编写。

(define (read-file file-name)
  (call-with-input-file file-name
    (lambda (p)
      (let loop((ls1 '()) (c (read-char p)))
    (if (eof-object? c)
        (begin
          (close-input-port p)
          (list->string (reverse ls1)))
        (loop (cons c ls1) (read-char p)))))))

(with-input-from-file filename procedure) 该函数将名为filename的文件作为标准输入打开。函数procedure不接受任何参数。当procedure退出时,文件自动被关闭。[代码片段3]展示了如何用with-input-from-file来重写[代码片段1]。

(define (read-file file-name)
  (with-input-from-file file-name
    (lambda ()
      (let loop((ls1 '()) (c (read-char)))
    (if (eof-object? c)
        (list->string (reverse ls1))
        (loop (cons c ls1) (read-char)))))))

read

函数(read port)从端口port中读入一个S-表达式。用它来读诸如”paren.txt”中带括号的内容就很方便。

'(Hello world!
Scheme is an elegant programming language.)

'(Lisp is a programming language ready to evolve.)
[代码片段4]

(define (s-read file-name)
  (with-input-from-file file-name
    (lambda ()
      (let loop ((ls1 '()) (s (read)))
    (if (eof-object? s)
        (reverse ls1)
        (loop (cons s ls1) (read)))))))

下面展示了用s-read读取”paren.txt”的结果。

(s-read "paren.txt")
⇒ ((quote (hello world! scheme is an elegant programming language.))
(quote (lisp is a programming language ready to evolve.)))

练习1

编写函数(read-lines),该函数返回一个由字符串构成的表,分别代表每一行的内容。在Scheme中,换行符是由#\Linefeed表示。下面演示了将该函数用于”hello.txt”的结果。

(read-lines "hello.txt") ⇒ ("Hello world!" "Scheme is an elegant programming language.")

输出至文件

打开一个用于输出的port

输出有和输入类似的函数,比如:

(open-output-file filename)

该函数打开一个文件用作输出,放回该输出端口。

(close-output-port port)

关闭用于输出的端口。

(call-with-output-file filename procedure)

打开文件filename用于输出,并调用过程procedure。该函数以输出端口为参数。

(with-output-to-file filename procedure)

打开文件filename作为标准输出,并调用过程procedure。该过程没有参数。当控制权从过程procedure中返回时,文件被关闭。

用于输出的函数

下面的函数可用于输出。如果参数port被省略的话,则输出至标准输出。

(write obj port) 该函数将obj输出至port。字符串被双引号括起而字符具有前缀#\。
(display obj port) 该函数将obj输出至port。字符串不被双引号括起而字符不具有前缀#\。
(newline port) 以新行起始。
(write-char char port) 该函数向port写入一个字符。

练习2

编写函数(my-copy-file)实现文件的拷贝。

练习3

编写函数(print-line),该函数具有任意多的字符作为参数,并将它们输出至标准输出。输出的字符应该用新行分隔。

JSRUN闪电教程系统是国内最先开创的教程维护系统, 所有工程师都可以参与共同维护的闪电教程,让知识的积累变得统一完整、自成体系。 大家可以一起参与进共编,让零散的知识点帮助更多的人。
X
支付宝
9.99
无法付款,请点击这里
金额: 0
备注:
转账时请填写正确的金额和备注信息,到账由人工处理,可能需要较长时间
如有疑问请联系QQ:565830900
正在生成二维码, 此过程可能需要15秒钟