17387

[code]

    (with-open-file (s f :direction :input :element-type 'unsigned-byte)
      (let ((x (make-array 4 :element-type 'unsigned-byte)))
        (read-sequence x s)
        x))
    
[/code]

このようにファイルから変数xに4byte読みだすことは出来たのですが，それを4byteの整数に変換するにはどうすればよいのでしょうか．  
あるいは4byteの整数として直接読み込むことが出来るのでしょうか？

補足：  
wavファイルをparseするコードを自分で書こうと思って質問しました。  
wavファイルのヘッダ情報はデータサイズがそれぞれ異なるので、どうしたらそれを分解できるかなと思った次第です。


CC BY-SA 3.0
2015-10-07T12:11:24.413
17374
2015-10-09T04:09:10.653
2015-10-09T04:09:10.653
12467
12467
question
common-lisp
ファイルから4byteの整数を読みだす


ファイルから 4 バイト(32 ビット)単位で読み込む様にして、`read-byte` で読み出せばよろしいかと思います。

[code]

    (with-open-file (s "file" :direction :input :element-type '(unsigned-byte 32))
                    (read-byte s))
    
[/code]

`element-type` が `'(unsigned-byte 32)` の場合は `unsigned int`、 `'(signed-byte
32)` とすれば `signed int` として扱われる事になります。

例えば、以下の様にしてサンプルデータを作成して、

[code]

    $ perl -e "print pack('L', -10000)" > int.dat
    
[/code]

SBCL で読み込んでみます。

[code]

    * (with-open-file (s "int.dat" :direction :input :element-type '(signed-byte 32))
                      (read-byte s))
      => -10000
    
    * (with-open-file (s "int.dat" :direction :input :element-type '(unsigned-byte 32))
                      (read-byte s))
      => 4294957296
    
[/code]

**追記**

Quicklisp に [cl-binary-file](http://quickdocs.org/cl-binary-file/api) という
package がありました…。`signed/unsigned`, `little-endian/big-endian`
の指定ができるので、こちらの方が良いかもしれません。

[code]

    * (ql:quickload :cl-binary-file-0.4)
    * (use-package :binary-file)
    * (read-integer (open-binary-stream "int.dat") :bytes 4 :signed t :endianness :little-endian)
      => -10000
    * (read-integer (open-binary-stream "int.dat") :bytes 4 :signed nil :endianness :little-endian)
      => 4294957296
    
[/code]

※ SBCL では `sb-c:*backend-byte-order*` でシステムの byte order を取得できます。

[code]

    * sb-c:*backend-byte-order*
    
    :LITTLE-ENDIAN
    
[/code]

**追記その2**

> 同じファイルから4byteの整数以外にバイト列(unsigned-byte 8)も取得したい場合、element-
> typeを切り替えながら読み込むということは可能なのでしょうか？

はい、以下の様に `with-open-file` を2重にします。

[code]

    (with-open-file (s "int.dat" :direction :input :element-type 'unsigned-byte)
      (with-open-file (int32 "int.dat" :direction :input :element-type '(signed-byte 32))
                      (let ((x (make-array 4 :element-type 'unsigned-byte)))
                        (read-sequence x s)
                        (list x (read-byte int32)))))
    
    => (#(240 216 255 255) -10000)
    
[/code]


CC BY-SA 3.0
2015-10-07T18:09:03.657
17387
2015-10-08T05:06:13.503
2015-10-08T05:06:13.503
17374
answer


  * オクテット(unsigned-byte 8)を読み出す
  * 4オクテット単位でまとめたい(unsigned-byte 32として読む)
  * 途中でub8<=>ub32を切り替える(且つ切り換え場所から読み込み)

となると [nibbles](http://quickdocs.org/nibbles/) を使うのが簡単かなと思います。  
ライブラリを使わないのならば、オクテットで読み出してエンディアンを考慮しつつ合成するか、ub32で読んでエンディアンを考慮しつつ分解するか、かなと思います。

[code]

    (ql:quickload :nibbles)
    
    ;; ファイル作成
    (with-open-file (out "/tmp/foo.bin" 
                         :element-type '(unsigned-byte 8) 
                         :direction :output
                         :if-does-not-exist :create
                         :if-exists :supersede)
      (dotimes (i 32)
        (write-byte 255 out)
        (write-byte 0 out)))
    
    
    ;; 読み出し
    (with-open-file (in "/tmp/foo.bin" :element-type '(unsigned-byte 8))
      (let ((ans (list (nibbles:read-ub32/be in) ;unsigned-byte 32/big endian
                       (nibbles:read-ub32/le in) ;unsigned-byte 32/little endian
                       (read-byte in) ;unsigned-byte 8
                       (read-byte in) ;unsigned-byte 8
                       (read-byte in) ;unsigned-byte 8
                       (read-byte in) ;unsigned-byte 8
                       )))
        (format T "~&~{~12D: ~:*#b~32,'0B~%~}" ans)))
    ;>>  4278255360: #b11111111000000001111111100000000
    ;>>    16711935: #b00000000111111110000000011111111
    ;>>         255: #b00000000000000000000000011111111
    ;>>           0: #b00000000000000000000000000000000
    ;>>         255: #b00000000000000000000000011111111
    ;>>           0: #b00000000000000000000000000000000
    ;=> nil
    
[/code]


CC BY-SA 3.0
2015-10-08T17:41:07.317
17435
2015-10-08T17:41:07.317
3510
17374
answer