ファイルを読み込んで文字列に格納すると終端にNULL文字が入る

[code]

    (with-open-file (s "test.txt" :direction :input)
     (let ((buf (make-string (file-length s))))
      (read-sequence buf s)
      buf))
    
[/code]

↑のようにread-
sequenceで日本語で書かれたファイル(ここではtest.txt)を読み込んで文字列に格納すると，その文字列にNULL文字が入ってしまいます．  
例えばtest.txtの中身が

[code]

    日本語で書かれた文章
    
[/code]

であった場合，格納される文字列は

[code]

    "日本語で書かれた文章^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@"
    
[/code]

となってしまいます。

格納する変数のサイズの指定が悪いと思うのですが，どうすればピッタリ格納出来るでしょうか？  
ちなみに処理系はsbclでファイルの文字コードはUTF-8です。




現象として、日本語のファイルを読んだらNull文字でパディングされたように見えているだけで、実際に起きていることは違います。

### make-string

`make-string`は指定した長さの文字列を作りますが、未指定の場合の初期値は処理系によって違います。  
SBCLの場合は、Null文字であった、というだけです。

[code]

    (make-string 10)
    ;=> "^@^@^@^@^@^@^@^@^@^@" 
    
[/code]

### read-sequence

`read-sequence`は、用意されたシーケンス(文字列もシーケンス)に読み込んだものを植え付けます。

この2つが合さって、Null文字でパディングされているように見えた、ということになります。  
日本語かどうかと、何でパディングされるか、は無関係ということになります。

[code]

    (with-open-file (s "/tmp/j.txt" :direction :input)
     (let ((buf (make-string (file-length s) :initial-element #\Space))); 初期値に空白を与えた場合
      (read-sequence buf s)
      buf))
    ;=> "日本語で書かれた文章                    " 
    
[/code]

## 日本語のテキストを読み込むには

日本語のテキストを読み書きするのに、オクテットに変換することはまず無く、大抵は、単にエンコーディングを合わせて`read-line`するだけです。

[code]

    (with-open-file (s "test.txt" :direction :input :external-format :utf-8)
      (let ((buf (read-line s)))
        buf))
    ;=> "日本語で書かれた文章" 
    
[/code]

なお、複数行の場合はファイル終端まで繰り返します。

[code]

    (with-open-file (s "test.txt" :direction :input :external-format :utf-8)
      (loop :for line := (read-line s nil) :while line
            :collect line))
    ;=> ("日本語で書かれた文章") 
    
[/code]

もしくは read-sequence で一気に読み込みます

[code]

    (with-open-file (s "/tmp/j.txt"
                       :direction :input
                       :element-type '(unsigned-byte 8)
                       :external-format :utf-8)
      (let ((buf (make-array (file-length s) :element-type '(unsigned-byte 8))))
        (read-sequence buf s)
        (sb-ext:octets-to-string buf :external-format :utf-8)))
    ;=> "日本語で書かれた文章
    
[/code]

; "




現象として、日本語のファイルを読んだらNull文字でパディングされたように見えているだけで、実際に起きていることは違います。

### make-string

`make-string`は指定した長さの文字列を作りますが、未指定の場合の初期値は処理系によって違います。  
SBCLの場合は、Null文字であった、というだけです。

[code]

    (make-string 10)
    ;=> "^@^@^@^@^@^@^@^@^@^@" 
    
[/code]

### read-sequence

`read-sequence`は、用意されたシーケンス(文字列もシーケンス)に読み込んだものを植え付けます。

この2つが合さって、Null文字でパディングされているように見えた、ということになります。  
日本語かどうかと、何でパディングされるか、は無関係ということになります。

[code]

    (with-open-file (s "/tmp/j.txt" :direction :input)
     (let ((buf (make-string (file-length s) :initial-element #\Space))); 初期値に空白を与えた場合
      (read-sequence buf s)
      buf))
    ;=> "日本語で書かれた文章                    " 
    
[/code]

## 日本語のテキストを読み込むには

日本語のテキストを読み書きするのに、オクテットに変換することはまず無く、大抵は、単にエンコーディングを合わせて`read-line`するだけです。

[code]

    (with-open-file (s "test.txt" :direction :input :external-format :utf-8)
      (let ((buf (read-line s)))
        buf))
    ;=> "日本語で書かれた文章" 
    
[/code]

なお、複数行の場合はファイル終端まで繰り返します。

[code]

    (with-open-file (s "test.txt" :direction :input :external-format :utf-8)
      (loop :for line := (read-line s nil) :while line
            :collect line))
    ;=> ("日本語で書かれた文章") 
    
[/code]

もしくは read-sequence で一気に読み込みます

[code]

    (with-open-file (s "/tmp/j.txt"
                       :direction :input
                       :element-type '(unsigned-byte 8)
                       :external-format :utf-8)
      (let ((buf (make-array (file-length s) :element-type '(unsigned-byte 8))))
        (read-sequence buf s)
        (sb-ext:octets-to-string buf :external-format :utf-8)))
    ;=> "日本語で書かれた文章
    
[/code]

; "

