ファイル入出力
Emacs LispでCIIフォーマットをテキスト処理してみよう。以下、*scratch*バッファでC-j。
EmacsはOSの提供するファイルに対してバッファを割り当てており、
実際にはバッファに対して操作することになる。
- ファイルを開く=バッファを割り当てる
(find-file "~/test.cii")
EmacsでC-x C-fしたのと一緒。
- ファイルを開く=バックグラウンドでバッファを割り当てる
(find-file-noselect "~/test.cii") #<buffer test.cii>
- ファイルを例えば先頭から251バイト読む#1
(insert-file-contents "~/test.cii" nil 0 251) ("c:/meadow/test.cii" 251) 0C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011--------------------------------------------------------------------------------------------------------------------------------------------------------
ん?この結果はなんだろう?
(setq x (insert-file-contents "~/test.cii" nil 1 251)) ("c:/meadow/test.cii" 250) C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011-------------------------------------------------------------------------------------------------------------------------------------------------------- x ("c:/meadow/test.cii" 250)
どうも、insert-file-contents は、ファイル名とサイズのリストを返す際の
副作用として、結果をカレントバッファ(ここでは*scratchバッファ)に挿入するようだ。
うーん、これは、ファイルを読む+カレントバッファに挿入の2つの動作をしている。
ここでは、むしろ、カレントバッファに挿入した内容をまず、取得したいんだが…。
- ファイルの先頭251バイトを読んで文字列を取得する
(setq f (find-file-noselect "~/test.cii")) #<buffer test.cii> (set-buffer f) #<buffer test.cii> (buffer-substring 0 251) Debugger entered--Lisp error: (args-out-of-range 0 251) buffer-substring(0 251) eval ( (buffer-substring 0 251) ) eval-last-sexp-1(t) eval-last-sexp(t) eval-print-last-sexp() call-interactively(eval-print-last-sexp)
あれエラーになった。qでデバッガから復帰。もういっちょ。
(buffer-substring 1 251) #("(setq f (find-file-noselect \"~/test2.cii\")) #<buffer test2.cii> (set-buffer f) #<buffer test2.cii> (buffer-substring 1 251)
ん?なんか、*scratch*バッファの内容をそのまま先頭からコピーしてるような…。
バッファの切り替えset-bufferと文字列の取得buffer-substringを一連の処理として
評価しないといかんのだな。
こうか?
(save-excursion (set-buffer f) (buffer-substring 1 251) ) "0C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011-------------------------------------------------------------------------------------------------------------------------------------------------------" (setq str (save-excursion (set-buffer f) (buffer-substring 1 251) )) "0C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011-------------------------------------------------------------------------------------------------------------------------------------------------------" str "0C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011-------------------------------------------------------------------------------------------------------------------------------------------------------"
OK、OK。
- ファイルから251バイト単位でシーケンシャルに読む
関数を定義する。
(defun seq-read (f begin) (save-excursion (set-buffer f) (buffer-substring begin (+ begin 251)) ))
しかし、いちいち、ファイルの読み出し位置を指定するのは、うまくない。
うーん…、ポイントを使えばいいようだ。
ファイルの終わりまで来た時は、nilを返してEOFとしよう。
(defun seq-read (f) (save-excursion (set-buffer f) (if (>= (point (point-max)) nil (buffer-substring (point) (+ (point) 251)) )) (defun seq-succ (f) (save-excursion (set-buffer f) (if (>= (point) (point-max)) nil (goto-char (+ (point) 251)) ) )) (seq-read f) "0C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011--------------------------------------------------------------------------------------------------------------------------------------------------------" (seq-succ f) 252 (seq-read f) "9D00001^@\371-----22222233444444444444555555555555666666666666777777777777888899900011-----------------------------------------------------------------------------------------------------------------------------------------------------------------------\376 "
うーん、seq-read と seq-succ は、構造がほとんど同じ上に別々に評価しないといけない。
seq-readで本当にやりたいことは、ファイルから読んだ文字列を返すと同時に、
読み込む位置を次にずらすことだ。
こういうときは、prog1を使うといいようだ。
これで、完成かな。ついでに、ポイントを巻き戻す関数も作っておこう。
(defun seq-read (f) (save-excursion (set-buffer f) (if (>= (point) (point-max)) nil (prog1 (buffer-substring (point) (+ (point) 251)) (goto-char (+ (point) 251)))) )) (defun seq-rewind (f) (save-excursion (set-buffer f) (goto-char (point-min)) )) (seq-read f) "0C0111111111111222222222222333333333333444444444444555555555555666666666666777777777777888899900011--------------------------------------------------------------------------------------------------------------------------------------------------------" (seq-read f) "9D00001^@\371-----22222233444444444444555555555555666666666666777777777777888899900011-----------------------------------------------------------------------------------------------------------------------------------------------------------------------\376 "