2013

8

19

HTML5のFile APIでローカルファイル情報取得してやんよ!!!

スポンサードリンク


そろそろHTML5 APIのひとつでもリファレンスしていこうかな・・・
かといって今さらcanvasとかやってもしょうがないし、MathMLみたいなマニアックなものは覚えても使う機会があるかどうか・・・という事で

『File API』というヤツを手始めに覚えようかと思います。

『File API』について

HTML5以前はブラウザ(またはWebアプリ)からローカルファイルを扱うには<input type=”file”>タグを利用してユーザーがファイルをアップロードする必要がありましたが、File APIの登場でJavaScriptからローカルファイルを直接読み取ることができる様になりました。

このAPIはユーザーが指定したローカルファイル(Webブラウザが動作するパソコンのHDDやSSDといったストレージに置かれたファイル)の情報やデータを取得できます。
File APIにはローカルファイルの読み取りだけでなく、書き込みやファイルを操作するAPIも用意されています。

File API

ファイル読み取りを行うAPI

File API:Writer

ファイルへの書き込みを行うAPI

File API:Directories and System

ディレクトリ階層内にフォルダやファイルの作成・保存を行うAPI

書き込み・保存ができる様になったといっても、File APIでアクセスできるのはあくまでユーザーが指定したファイルだけになります。
セキュリティの問題上でパスを「C:\file.txt」や「../text/file.txt」の様に指定してファイルを書き直す事はできません。

主要ブラウザのFile APIへの対応状況

ブラウザ 対応バージョン
Internet Explorer 10.0
Fire Fox 3.6以降
Chrome 6.0以降
Safari 5.1以降
Opera 11.1以降
まぁまず各主要ブラウザの最新版を使っていれば問題無く実装されている様です。

if(window.File && window.FileReader) {
	//File API
	alert("ご使用のブラウザはFile APIを実装しています");
}else{
	alert("ご使用のブラウザはFile APIをサポートしていません");
}
一応こちらのテスト用スクリプトを使えば使用するブラウザがFile APIに対応しているかがわかります。

①ローカルファイルの情報を取得する

情報を取得するファイル選択は<input>タグを使用します。
複数のファイルを選択できる様にmultiple属性を用います。

HTML

<input id="loadFile" type="file" multiple>

JavaScript

function loadFile_changeHandler(e){
	var files = e.target.files;
	var fileData = "";
	for(var i = 0; i < files.length; i++){
		var fileVal = files[i];
		fileData +=
			'ファイル名:' + escape(fileVal.name) + '<br>' +
			'ファイルサイズ:' + fileVal.size + ' バイト<br>' +
			'MIMEタイプ:' + fileVal.type + '<br>' +
			'最終更新日時:' + fileVal.lastModifiedDate + '<hr>';
		}
	$('#info').innerHTML = fileData;
}

function $(id) {
	return document.querySelector(id);
}
これで指定したファイルの「ファイル名」、「ファイルサイズ」、「MIMEタイプ」、「最終更新日時」の各パラメーターが変数filesの配列内に格納されます。
こちらのデモページでローカルファイルを選択してください。

②ファイルの内容を読み取る

ローカルファイルの読み取りにはFile APIの『File Reader』オブジェクトを利用します。
テキストファイルだけでなく、画像などのバイナリファイルも読み取りが可能です。
読み取りメソッド 説明
readAsBinaryString(File) 非同期にファイルを読み取り
バイナリ文字列を取得
readAsText(File, enc) 非同期にファイルを読み取り、テキスト文字列を返します。
文字エンコーディングを指定する引数encを省略すると「UTF-8」として読み取ります
readAsDataURL(File) 非同期にファイルを読み取り、Data URIにエンコードされたデータを返します
readAsArrayBuffer(File) 非同期にファイルを読み取り、ArrayBufferオブジェクトとしてデータを返す

HTML

<input id="loadFile" type="file" multiple><br>
<textarea id="info"></textarea>
formタグにて画像のアップロードフォームを定義

JavaScript

	$("#loadFile").onchange = function(evt){
		var file = evt.target.files[0];
		if(!file.type.match(/text/)){
			alert('テキストファイルを' + '選んで下さい');
			return;
	}
	
	var reader = new FileReader();
	reader.onload = function(evt) {
		$("#info").value = evt.target.result;
	}
	
	reader.readAsText(file, "Shift_JIS");
	}
	
	function $(id) {
		return document.querySelector(id);
	}
こちらのデモページでローカルのテキスト形式のファイルを選択してください。

デモページ解説

  • ①”非同期”でファイルの読み取りが完了するとonloadイベントが発生し、ファイル内容はonloadイベントのイベントハンドラ内で受け取ったデータはtarget.resultプロパティに格納されます。
  • ②ユーザーがファイルを選択すると、onchangeイベントが発生するので、このイベントを補足するためのイベントハンドラを指定します。
  • ③イベント引き数のtarget.filesプロパティにアクセスして、ファイル情報を調べます。
    MIMEタイプを表すtypeプロパティをチェックして「text」が含まれていないなら読み取れない旨のメッセージを表示します。
  • ④FileReaderのオブジェクトを作成します。
  • ⑤その後、同オブジェクトでreadAsTextメソッドを実行し、読み取りを開始します。
  • ⑥読み取りが完了した際にはonloadイベントが発生するので、onloadプロパティにイベントハンドラを登録しておきます。
  • このイベントハンドラでは、イベント引数のtarget.resultプロパティを参照して、読み取られたテキストを <textarea>に表示します。
  • ※readAsTextメソッドでは、第2引数に”Shift_JIS”を指定しているので、文字コードがShift_JISのテキストを正しく読み取ることができます。このメソッドは、テキストエンコーディングを自動判定できないので文字コードが合致していないと文字化けを起こします。

③画像のファイルのサムネイルを表示する

FileReaderオブジェクトのreadAsDataURLメソッドを使うと、ファイルを読み取り、URLエンコードされたデータを取得できます。

HTML

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input id="afile" type="file" name="img"><br>
	<img id="thumb" width="320">
    <input id="up_btn" type="submit" value="アップロード" />
</form>        //①

JavaScript

	showImage(false);
	
	$("#afile").onchange = function(evt){
		showImage(false);
		var files = evt.target.files;
		if(files.length == 0) return;
		var file = files[0];
		if(!file.type.match(/image/)) {
			alert('画像ファイルを選んでください');
			return;
		}        //②
		var reader = new FileReader();        //③
		reader.onload = function(evt) {
			$("#thumb").src = reader.result;
			showImage(true);
		}
		reader.readAsDataURL(file);
	}
	
	function showImage(b) {
		var val = b ? "block" : "none";
		$("#up_btn").style.display = val;
		$("#thumb").style.display = val;
	}        //④
	
	function $(id) {
		return document.querySelector(id);
	}
選択した画像のファイルのサムネイルを表示させるデモがこちら

デモページ解説

  • ①<form>~</form>ではPHPスクリプトの専用CGI「upload.php」へ画像ファイルをアップロードを想定し、画像のアップロードフォームを定義。
  • ②スクリプトでははじめに画像とアップロードボタンを非表示しユーザーがファイル選択したときのonchangeイベントのために、onchangeプロパティにイベントハンドラを設定し、MIMEタイプを調べてファイルが画像かどうか判定します。
  • ③そして、FileReaderオブジェクトのreadAsDataURLメソッドを利用して画像ファイルを読み取ります。
  • ④非同期に読み取り、onloadイベントが発生するとresultプロパティを参照することで読み取られたデータを取得できます。その後、<img>タグとアップロードを表示します。

④バイナリファイルを解析する

FilereaderオブジェクトのreadAsBinaryStringメソッドを利用したバイナリファイルの解析は同メソッドで読み取ったデータはJavaScriptの文字列として取得できます。(1バイトが1文字のデータ)文字列なのでcharCodeAtやcharAt等の文字列が持つ各種メソッドを利用できます。

HTML

	<input id="afile" type="file"><br>
	<div id="info"></div><br>
	<img id="thumb" width="320">

JavaScript

	var targetfile = null;
	
	$("#afile").onchange = function(evt){
		var files = evt.target.files;
		if(files.length == 0) return;
		targetFile = files[0];
		var reader = new FileReader();
		reader.onload = readPNGFile;
		reader.readAsBinaryString(targetFile);        //①
	}
	//②
	function readPNGFile(evt) {
		var bin = evt.target.result;
		var sig = String.fromCharCode( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a);        //③、④
		var head = bin.substr(0, 8);
		if(sig != head) {
			alert("PNGファイルではありません");
			return;
		}
		
		var width = getBinValue(bin, 8 + 0x08, 4);
		var height = getBinValue(bin, 8 + 0x0c, 4);
		var depth = bin.charCodeAt(8 + 0x10);
		
		$("#info").innerHTML =
			"width: " + width + "px<br>" +
			"height: " + height + "px<br>" +
			"depth: " + depth + "bit";
		var reader = new FileReader();
		reader.onload = function(e) {
			$("#thumb").src = reader.result;
		}
		reader.readAsDataURL(targetFile)
	}        //⑤
	
	function getBinValue(bin, i, size) {
		var v = 0;
		for(var j= 0; j < size; j++){
			var b = bin.charCodeAt(i + j);
			v = (v << 8) + b;
		}
		return v;
	}        //⑥
	
	function $(id) {
		return document.querySelector(id);
	}

選択されたPNGファイルをバイナリファイルを解析するデモがこちら

デモページ解説

  • ①バイナリデータとしてデータを読み取るためFileReaderオブジェクトのreadAsBinaryStringメソッドを利用します。
  • ②非同期に読み取りを行い、読み取り完了時のonloadイベントでreadPNGFile関数でPNGファイルの解析を行う。
  • ③PNGファイルの先頭8バイトは、PNGファイルを識別するための固定シグネチャとなっています。そのため、冒頭8バイトを調べてPNGファイルかどうか判定しています。
  • ④String.fromCharCodeメソッドを使うと、特定のバイトからなる文字列を作成できます。これを利用してPNGファイルのシグネチャ文字列を作成しています。また、String.substrメソッドを利用すれば、文字列の一部を切り取ることができます。文字列を比較することで連続するバイナリがPNGファイルのシグネチャかどうかを判定できます。
  • ⑤PNG画像であるか判明したら、サムネイルを表示し、readAsDataURLメソッドを利用してimgタグのsrc属性に読み取ったデータを設定します。
  • ⑥バイナリデータの解析では、複数バイトからなる数値を読み取る必要があり、これを行うのがgetBinValue関数です。
  • ※PNG画像の幅や高さは、4バイトの数値として記録されるので、同関数を利用して4バイトのバイナリの文字列を、シフト演算などを使って数値に変換しています。


トップへ