はじめに
JavaScriptでローカルにある単精度浮動小数点数型データ(float32)のバイナリデータを読みこむサンプル。
バイナリデータの作成
まず、C/C++で言うところのfloat型をバイナリで保存する。
test.cpp
#include <cstdio>
#include <cstdlib>
int
main(void){
const int N=10;
float a[N];
for(int i=0;i<N;i++){
a[i] = 1.1*(i+1);
printf("%f\n",a[i]);
}
FILE *fp = fopen("test.dat","w");
fwrite((char*)a,sizeof(float),N,fp);
}
コンパイル、実行すると、test.dat
が生成されるので中身を見てみる。
$ g++ test.cpp
$ ./a.out
$ od -tfF test.dat
0000000 1.100000e+00 2.200000e+00 3.300000e+00 4.400000e+00
0000020 5.500000e+00 6.600000e+00 7.700000e+00 8.800000e+00
0000040 9.900000e+00 1.100000e+01
0000050
1.1から11までの数字がバイナリで保存されている。
JavaScriptでの読み込み
こんなHTMLを書く。
test.html
<!DOCTYPE html>
<html>
<head>
<title>Float32 Sample</title>
</head>
<body>
<input type="file" id="file" accept=".dat">
<ul id="data"></ul>
<script>
function onFileSelect(e) {
var f = e.target.files;
var reader = new FileReader();
reader.onload = function(filename){
a = new Float32Array(reader.result);
list = $('data');
var s = "";
a.forEach(function(v){
s = s + "<li>" + v.toFixed(6);
})
list.innerHTML=s;
}
reader.readAsArrayBuffer(f[0]);
}
$('file').addEventListener('change', onFileSelect, false);
function $(id){
return document.getElementById(id);
}
</script>
</body>
</html>
処理はこんな感じ。
- ファイルを読み込むinputタグの
change
イベントに対して、FileReader
オブジェクトreader
のreadAsArrayBuffer
でロードする。 -
readAsArrayBuffer
は非同期なので、予めreader.onload
にロードが完了した時の処理を書いておく。 - 読み込まれたデータは
reader.result
に貼っているので、それをFloat32Array
を使ってfloat32
の型付き配列として読みこむ。 -
Float32Array
のforEach
はコールバック関数を取る。コールバック関数の引数に配列の中身が順番に入ってくるので、ここではそれをリストに追加している。
実行結果
先程のtest.html
を開くとこんな画面になる。
参照ボタンを押して、先程作成したtest.dat
を開くと、中身が表示される。
ちゃんと読めているようですね。
ハマりポイント
いつくかハマったところなど。
- ローカルファイルは
window.onload
などでは読み込めず、ユーザが明示的に指定する必要がある(セキュリティのため)。 -
Float32Array(reader.result)
で読み込んだ配列にたいして、for(var v in a)
みたいなfor文を書くと、v
がString
型になってしまい、かつ整数に丸められたものになってしまう。for(var i=0;i<a.length;i++)
みたいにしてa[i]
でアクセスするのはOK。1
-
素直に配列で回すのとコールバック関数使うのとどちらが良いのかは知りません。 ↩