HTML5 File API 구현




HTML5 File API 구현



웹 브라우저(Gecko, Webkit 등..)상에서 로컬 영역의 특정 파일을 접근, 조작할 수 있는 여러가지 방법을 제공합니다.


단 제공되는 File Interface는 로컬 보안 상 파일 탐색기 또는 Drag & Drop 방식을 이용해 사용자가 직접 선택한 File로 한정 시킵니다.




아래는 관련 소스를 모듈화 시킨 코드이며, 각 기능은 아래와 같습니다.



1. 생성자 함수:

File(form || undefined)

form: 해당 File 컨트롤을 포함하는 부모 엘리먼트(보통 Form 엘리먼트가 해당됨)




2. 각 File 컨트롤의 onchange 이벤트 등록

.change(callback);

callback: onchange 이벤트 시 핸들러




3. 각 Drop Zone 엘리먼트의 dragenter 이벤트 등록

.dragenter(elems, callback)

elems: 엘리먼트 or 엘리먼트 배열

callback: ondragenter 이벤트 시 핸들러




4. 각 Drop Zone 엘리먼트의 dragleave 이벤트 등록

dragleave(elems, callback)

elems: 엘리먼트 or 엘리먼트 배열

callback: dragleave 이벤트 시 핸들러




5. 각 Drop Zone 엘리먼트의 dragover 이벤트 등록

dragover(elems, callback)

elems: 엘리먼트 or 엘리먼트 배열

callback: dragover 이벤트 시 핸들러




6. 각 Drop Zone 엘리먼트의 dragdrop 이벤트 등록

dragdrop(elems, callback)

elems: 엘리먼트 or 엘리먼트 배열

callback: dragover 이벤트 시 핸들러




7. progress 관련 이벤트 등록

progress(data, before, update, load, dataType)

data: file 객체

before: 읽어드린 file 객체의 onloadstart 이벤트 시 핸들러

update: 읽어드린 file 객체의 onprogress 이벤트 시 핸들러

load: 읽어드린 file 객체의 onload 이벤트 시 핸들러

dataType: file 객체의 저장 데이터 타입




8. file 객체 반복자

File.each(files, callback, type)

files:컨트롤을 통해 선택된 파일 리스트

callback: 각 컨트롤의 반복자 callback

type: 허용 file 타입




9. 파일 읽기

Fil.read(data, callback, dataType)

data: 읽어드릴 file 객체

callback: 읽어드린 file 객체의 onload 이벤트 시 핸들러

dataType: file 객체의 저장 데이터 타입




10. Blob 생성

File.readBlob(data, start, end, callback)

data: 읽어드릴 file 객체

start: 시작 바이트 배열 index

end: 마지막 바이트 배열 index

callback: 읽어드린 file 객체의 onload 이벤트 시 핸들러





- 관련된 자세한 소스는 아래 jsbin.com에 등록된 페이지를 살펴 보시기 바랍니다.






1. JSBin 소스 링크:

http://jsbin.com/urupic/2




2. 모듈 사용방법:

  window.onload = function (e) {
        //var target = document.getElementById('spin');
        //var spinner = new Spinner(opts).spin(target);

        var zone1 = document.getElementById('drop_zone1');
        var zone2 = document.getElementById('drop_zone2');
        var zone3 = document.getElementById('drop_zone3');

        var zones = [zone1];

        var progress = document.getElementById('progress_bar');
        var progress_percent = document.getElementById('progress_percent');

        File().change(function (e, files) {

            zone1.innerHTML = "Loading...";

            var that = this;
            var h = [];

            File.each(files, function (idx) {

                File.read(this, function (e, result) {

                    var html = '<li>';
                    html += '<div style="margin-top:20px;margin-left:10px;">';
                    html += '<img src="' + result + '" width="200" height="200" style="border:gray 2px solid" />';
                    html += '<div style="margin-top:10px"> name: ' + escape(this.name) + ' type: ' + this.type + ' size: ' + this.size + ', lastModifiedDate: ' + this.lastModifiedDate + ',' + this.lastModifiedDate.toLocaleDateString() + '</div>';
                    html += '<textarea style="margin-top:10px;width:600px;height:200px">' + result + '</textarea>';
                    html += '</div>';
                    html += '</li>';

                    h.push(html);

                    if (idx >= files.length - 1) document.getElementById('image_list').innerHTML += h.join('');

                }, 'dataUrl');

                /*
                File.readBlob(this, 0, this.size, function (e, result) {
                });
                */

                that.progress(this, function (e) {
                    progress_percent.style.width = '0%';
                    progress_percent.textContent = '0%';

                    progress.className = 'loading';
                },
			    function (e, loaded, total) {

			        var percent = Math.round((loaded / total) * 100);

			        if (percent < 100) {
			            progress_percent.style.width = percent + '%';
			            progress_percent.textContent = percent + '%';
			        }
			    },
			    function (e) {
			        progress_percent.style.width = '100%';
			        progress_percent.textContent = '100%';

			        if (idx >= files.length - 1) {
			            zone1.innerHTML = "Upload Complete";
			            window.setTimeout(function () { progress.className = ''; }, 2000);
			        }
			    });

            }, 'image');
        })
	    .dragenter(zones, function (e, zone) {
	        zone.style.backgroundColor = 'orange';
	        zone.style.color = 'black';
	    })
	    .dragover(zones, function (e, zone) {
	        zone.style.backgroundColor = 'orange';
	        zone.style.color = 'black';
	    })
	    .dragleave(zones, function (e, zone) {
	        zone.style.backgroundColor = 'white';
	        zone.style.color = '#BBB';
	    })
	    .dragdrop(zones, function (e, files, zone) {

	        zone.innerHTML = "Loading...";

	        var that = this;
	        var h = [];

	        File.each(files, function (idx) {

	            File.read(this, function (e, result) {

	                var html = '<li>';
	                html += '<div style="margin-top:20px;margin-left:10px;">';
	                html += '<img src="' + result + '" width="200" height="200" style="border:gray 2px solid" />';
	                html += '<div style="margin-top:10px"> name: ' + escape(this.name) + ' type: ' + this.type + ' size: ' + this.size + ', lastModifiedDate: ' + this.lastModifiedDate + ',' + this.lastModifiedDate.toLocaleDateString() + '</div>';
	                html += '<textarea style="margin-top:10px;width:600px;height:200px">' + result + '</textarea>';
	                html += '</div>';
	                html += '</li>';

	                h.push(html);

	                if (idx >= files.length - 1) document.getElementById('image_list').innerHTML += h.join('');

	            }, 'dataUrl');

	            /*
	            File.readBlob(this, 0, this.size, function (e, result) {
	            });
	            */

	            that.progress(this, function (e) {
	                progress_percent.style.width = '0%';
	                progress_percent.textContent = '0%';

	                progress.className = 'loading';
	            },
			    function (e, loaded, total) {

			        var percent = Math.round((loaded / total) * 100);

			        if (percent < 100) {
			            progress_percent.style.width = percent + '%';
			            progress_percent.textContent = percent + '%';
			        }
			    },
			    function (e, result) {
			        progress_percent.style.width = '100%';
			        progress_percent.textContent = '100%';

			        if (idx >= files.length - 1) {
			            zone.style.backgroundColor = 'white';
			            zone.style.color = '#BBB';
			            zone.innerHTML = "Upload Complete";

			            window.setTimeout(function () { progress.className = ''; }, 2000);
			        }
			    });

	        }, 'image');
	    });
    }


    function bind(elem, type, handler, capture) {

        type = typeof type === 'string' && type || '';
        handler = handler || function () { ; };

        if (elem.addEventListener) {
            elem.addEventListener(type, handler, capture);
        }
        else if (elem.attachEvent) {
            elem.attachEvent('on' + type, handler);
        }

        return elem;
    };





3. 실행화면 및 브라우저 지원 상황:







- 브라우저 지원 상황:



http://caniuse.com/#feat=fileapi






5. 참고 사이트:


[HTML5강좌] 20. File API:

http://sqler.pe.kr/OSS/bIISLec/402253


Html5rocks File API:

http://www.html5rocks.com/en/tutorials/file/dndfiles/


W3c File API:

http://www.w3.org/TR/FileAPI/#dfn-Blob