상세 컨텐츠

본문 제목

html5, javascript ... 웹 파일 읽기/쓰기 업로드 가능 관련

WEB/JavaScript

by AlrepondTech 2020. 9. 20. 07:25

본문

반응형

 

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

 

출처: http://jongjongbari.tistory.com/92

 

ajax를 이용한 파일업로드 예제

공유/html 2014.04.15 18:52

XMLHttpRequest Level2 : XMLHttpRequest 사양이 발전한 형태로 아래 세가지 특징을 갖는다.

 

1. 크로스 도메인으로 요청을 송신할 수 있게 됨.

2. 파일이나 바이너리 데이터, 폼 데이터 등 송신할 수 있는 종류가 늘어남.

3. 요청 진행 상황을 확인할 수 있음(업로드/다운로드 모두)

 

 

fileupload.html

 

 

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>HTML5 실습 예제</title>
<style>
progress{
display: none;
}
</style>
<script>
window.onload = function(){
progress = document.querySelector("progress");
// upload 버튼을 클릭하면 파일을 업로드 한다.
document.querySelector("button").onclick = function(){
fileUpload();
}; 
};

// 파일을 업로드 한다.
function fileUpload(){
var uploadFile = document.querySelector("input");

var xhr = new XMLHttpRequest();

// 업로드 시작 -> xhr.download.onloadstart로 하면 download
xhr.upload.onloadstart = function(e){
progress.value = 0;
progress.style.display = "inline";
};

// 업로드 도중에 계속 발생 -> xhr.download.onprogress 하면 download
xhr.upload.onprogress= function(e){
// e.total : 전체 업로드 크기, e.loaded : 현재 업로드된 크기
progress.value = e.loaded/e.total;
console.log(progress.value);
};

// 업로드 종료 시 발생 -> xhr.download.onload 하면 download
xhr.upload.onload = function(e){
progress.style.display = "none";
};

xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
document.querySelector("div").innerHTML = xhr.responseText + "<br>";
}
};
xhr.open("POST", "http://localhost:8080/Html5Lab/ch18_etc/fileupload.jsp", true);
xhr.setRequestHeader("X-File-Name", encodeURIComponent(uploadFile.files[0].name));
xhr.send(uploadFile.files[0]);
}
</script>
</head>
<body>
<h1>XMLHttpRequest Level2를 이용한 파일 업로드</h1>
<input type="file">
<button>upload</button>
<progress>0%</progress><br>
<div></div>
</body>
</html>

 

 

fileupload.jsp

 

 

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page import="java.io.*" %>
<%
// 2번째 param에 명시된 서버만 서비스가 됨. 아래 코드는 모두 허용.
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "X-File-Name");

if(!"OPTIONS".equals(request.getMethod().toUpperCase())){
String fileName = request.getHeader("X-File-Name");
fileName = java.net.URLDecoder.decode(fileName, "UTF-8");
System.out.println(fileName);
String ext = fileName.substring(fileName.lastIndexOf("."));
String uploadFileName = fileName.substring(0, fileName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + ext;
File uploadDir = new File(application.getRealPath("fileupload"));
if(!uploadDir.exists()){
uploadDir.mkdir();
}
File uploadFile = new File(uploadDir, uploadFileName);

InputStream in = request.getInputStream();
OutputStream outFile = new FileOutputStream(uploadFile);
byte[] buf = new byte[1024*2];
int size = 0;
while((size=in.read(buf)) != -1){
outFile.write(buf, 0, size);
}
outFile.close();
in.close();

String fileUrl = application.getContextPath() + "/fileupload/" + uploadFileName;
out.write("<a href='"+fileUrl+"'>"+fileName+"</a>"); 
}
%>

 

 

=================================

=================================

=================================

 

 

출처: http://hellowk1.blogspot.kr/2015/07/formdata-file-submit-with-formdata.html

 

 

[FormData] File Submit With FormData(파일 전송하기)

Javascript에서 FormData로 파일 전송하기 


1. XMLHttpRequest 사용. 
2. $.ajax 사용.
3. AngularJS 시 $http 사용.

1. XMLHttpRequest사용.

기존에는 enctype="multipart/form-data" 를 해놓은 form을 form.submit()을 통해 파일을 전송하였지만, 자바스크립트에서 직접 폼 형태로 파일을 전송하기 위해 다음과 같이 FormData API를 사용하여 보낼 수 있습니다.

<form id="form1" name="form2">
    <input id="name" name="userName" type="text" value="John" />
    <input id="name" name="userAge" type="text" value="13" />
</form>

<script>
var form = document.forms.namedItem("form1"); 
var form = document.querySelector("#form1");
//forms.namedItem("폼 이름") , querySelector("#폼 id") 를 통해 
해당 form을 불러올수 있습니다.

var oData = new FormData(form);
//form 안에 input element 정보 반환.
var myRequest = new XMLHttpRequest();
 myRequest.onreadystatechange = function(){
  if(myRequest.readyState == 4 && myRequest.status == 200){
   console.log(myRequest.responseText);
  }
 };

myRequest.addEventListener("progress", updateProgress, false);
myRequest.open('post', 'get/data',true);
myRequest.send(oData);
</script>

FormData 객체는 폼의 각 필드와 값을 나타내는 키/값 쌍들의 집합을 쉽게 구성할 수 있는 방법을 제공하며, Content-type을 지정하지 않으면 FormData 사용 시 브라우저에서 데이터형식을 자동으로 “multipart/form-data”로 세팅하고 XMLHttpRequest의 send() 메소드를 통해 전송합니다. FormData 를 통해 전송할때 파일 전송이 아닐지라도 Content-Type을 지정하지 않으면 아래와 같이 전송됩니다.

------------------------------------------------------------------------------------------------
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryoSZuzFWLPtJdOCJL
Cookie:JSESSIONID=A0C15B87E2B501342824E3C38D80119A
Host:localhost:8989
Origin:http://localhost:8989
Referer:http://localhost:8989/girlsRuleShop/uploadPage
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Request Payload
------WebKitFormBoundaryoSZuzFWLPtJdOCJL
Content-Disposition: form-data; name="userName"

John
------WebKitFormBoundaryoSZuzFWLPtJdOCJL
Content-Disposition: form-data; name="userAge"

13
------WebKitFormBoundaryoSZuzFWLPtJdOCJL--
------------------------------------------------------------------------------------------------
즉 FormData는 Content-Type을 지정하지 않으면 multipart/form-data 형태로 전송됩니다.

 

2. jquery.ajax ($.ajax)

Method : POST일 경우 Content-Type은 아래와 같습니다.

- Content-Type : 'application/x-www-form-urlencoded; charset=UTF-8' (Default 값!!) 입니다.
data  형식은 say=Hi&to=Mom.로 전송되어집니다.
주로 $("#form1").serialize() 로 데이터를 보내며
Spring Controller에서는 @RequestParam 혹은 @ModelAttribute로 데이터를 받습니다.

- Content-Type : text/plain 일 경우
foo=bar
baz=The first line.
The second line.  와 같은 데이터 형식으로 전송됩니다.

- Content-Type : application/json 일 경우
{"foo":"bar","baz":"the first line"} 와 같은 데이터 형식으로 전송됩니다.
Spring Controller에서는 @Requestbody로 받는다.
@RequestBody로 받기 위해서는 JSON 형태의 데이터를 전송해야 한다.

- Content-Type : multipart/form-data 일 경우 
데이터 형식은 다음과 같이 생성됩니다.
Content-Type: multipart/form-data; boundary=boundary=----WebKitFormBoundary0DHFTrj22nQIn9E4
boundary=----WebKitFormBoundary0DHFTrj22nQIn9E4
Content-Disposition: form-data; name="foo"

bar
boundary=----WebKitFormBoundary0DHFTrj22nQIn9E4--

Content-Type:multipart/form-data; 이 뒤에 붙는 boundary는 데이터의 구분자로 사용됩니다.
전송되는 파일의 데이터 구분자로 사용되어 맨 뒤에 '--' 이 붙으면 데이터 Body의 끝을 알립니다.
Spring Controller에서는 MultipartHttpServletRequest를 통해 데이터를 받습니다.
$.ajax로 FormData 받기! 
     
      $.ajax({
          url: "upload/file",
          type: "POST",
          data: formData,
          processData: false,  // tell jQuery not to process the data
          contentType: false ,  // tell jQuery not to set contentType,
          success : function(data){
           console.log("doit"+data);
          } 
              }); 

$.ajax의 default Content-Type은 application/x-www-form-urlencoded 이며 이를 통해 
데이터를 전송할 경우 serialize 된 형태로 데이터가 전송됩니다. 
FormData로 전송하기 위해서는 아래와 같이 
processData : false, contentType : false로 세팅하여야 합니다.

contentType을 false를 해줌으로 써 브라우저로 하여금 FormData를 사용하여 전송 시 
자동으로 content-Type을 multipart/formdata로 세팅하고
correct boundary를 붙여 데이터를 보낼 수 있게 해줍니다.

ProcessData의 경우도 마찬가지로 data를 serialize를 하여 Query String으로 변경하기 때문에 
이를 막기 위해 false로 세팅해 줍니다.
(ProcessData : data를 query string의 형태로 변경시키는 옵션. default 값은 true)

 

 

3.AngularJs의 $http

AngularJS는 $http를 통해서 파일을 전송합니다.
$http의 경우 xhr를 base object로 가지고 있기 때문에 위에 $.ajax 와 똑같이 처리해주어야 합니다.

AngularJS는 $.ajax와 default Content-Type이 다릅니다.
AngularJs의 default Content-Type : application/json 이며
$.ajax의 processData와 같은 기능은 trnasformRequest function이 담당하고 있습니다. 
(trnasformRequest : The transform function takes the http request body and headers 
and returns its transformed (typically serialized) version.(JSON))

$.ajax 처럼 processData : false, contentType : false로 설정을 해주기 위해
AngularJs는 
 headers : {‘Content-Type’: undefined } 
 transformRequest : angular.identity 로 값을 주어야 합니다.

좀더 자세히 보자면,

Content-Type : 'undefined'가 $.ajax의 ContentType : false와 같은 의미이며 
'undefined' 값을 주어야 브라우저에서 자동적으로 'multipart/formdata'를 세팅하고 
correct boundary로 채워서 보내줍니다.

만약 Content-Type : 'multipart/form-data' 라고 직접적으로 명시하게 
된다면 오류가 발생합니다.
이렇게 직접적으로 명시해서 사용하기 위해서는 databoundary를 
직접 만들어 데이터를 이 boundary로 
감싸주는 코드를 구현해야합니다.

Content-Type과 transformRequest 모두 formData를 multipart/form-data로 
보낼 수 있게 설정해 주어야 합니다.
Content-Type: undefined 로 설정하고 transformRequest 에 대한 처리를 해주지 않으면
데이터는 제대로 전송되지 않습니다.
Content-Type에 맞는 transformed 된 데이터를 지정해주어 서버에 전송될 수 
있게하기 위해서 이를 담당하는 transformRequest()에서는 
$scope형태의 데이터를 FormData 형태로 만들어 transformed된 데이터를 return을 해주든지,
아니면 data option에 세팅해준 formData를 serialize 하지 않고 
그대로 보낼 수 있게 return data를해 주어야 합니다.

아래와 같이 3가지 형식으로 구현이 가능합니다.

----------------------------------------------------------------------------------------------------------
             $http.post('upload/file', formData, {
                 transformRequest: angular.identity,
                 headers: {'Content-Type': undefined }
       }).success(function(data){alert("성공");});

angular.identity 
=>function transformer(transformationFn, value) {
  return (transformationFn || angular.identity)(value);
};
----------------------------------------------------------------------------------------------------------
             $http({
               method: 'POST',
               url: 'upload/file',
               headers: {'Content-Type': 'undefined'},
               data: $scope.file1, 
               transformRequest: function(data,headersGetter) { 
               var formData1 = new FormData();
               formData1.append("file1", $scope.file1);              
              
               var headers = headersGetter();
               console.log(headers); // header 기본 정보 
                                      : Content-type: undefined.
                                        Accept: "application/json, text/plain.
               return formData1;
              }
       }).success(function (data) {
             alert("성공");
       }).error(function (data, status) {
       });
----------------------------------------------------------------------------------------------------------
            $http({
                 method: 'POST',
                 url: 'upload/file',
                 data: formData,
                 transformRequest: function(data,headersGetter) { 
                var headers = headersGetter();
                console.log(headers);
                headers['Content-Type'] = undefined;
                //or delete headers['content-Type']
                  return data;
                 }
         }).success(function (data) {
               alert("성공");
         }).error(function (data, status) {
         });
----------------------------------------------------------------------------------------------------------

 

 

=================================

=================================

=================================

 

 

출처: http://tastegod.co.kr/330

 

구글에 XmlHttpRequest 를 사용해서 하라는 가이드가 있어서 보다보니...

그거로만 되는건 아닌거 같음.

 

브라우저 콘솔에 이런게 뜨는데...이건 요청 브라우저단에서 크로스서버의 response 받기 전에 보여주는거 같기도 하다...

No 'Access-Control-Allow-Origin' header is present on the requested resource

 

크로스 서버로 요청이 아예 안들어가는건 아닌데, 제대로 들어가지는 않을것으로 보임.

 

파일처리서버는 내가 만든게 아닌데....

정 해야한다면 방법을 찾으면 되겠지만...  그냥 추후 서버를 합치는 방법으로 해야 할 거 같음.

추후 서버 합칠때.. Port가 다를 경우에도 cross-domain 에 걸린다고 하는데, 그땐 dataType 을 jsonp 로 하는 방법 등으로 처리하면 될 거 같다. 

아님 아예 완전 합쳐도 될 거 같고...

jQuery - Ajax - crossdomain 이슈
http://igna.tistory.com/19

단 에러처리가 안되기때문에.. 아래의 방법으로 해보는것도 가능할거 같다. 몇년전 자료라 요새 환경에서도 pass 될지는 모르겠다.

일단 접은 관계로... 더 테스트 해보진 않았다.

jQuery - Ajax - crossdomain 이슈 #2
http://igna.tistory.com/20



** 지금 다시보다보니... 크로스 서버쪽 allow header 설정에... X-Requested-With 넣어서 해봤어야 했는데 

Content-Type 
만 넣었었네... 쩝...  이거 넣어도 지금 요청 브라우저 자체에서 먼저 뭔가 하는거 같아서 안될거 같긴 하다.

참고 : res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
** 코딩한 소스 다 지워버렸는데... 사실 넣어봤자 현상황에 큰 도움이 안된다. 왜냐면 다음 포스트에 적을건데...
    현재 파일업로드후 파일이미지 정보를 받아와서 캔버스에 넣는데....
    cross-domain 이미지가 캔버스에 들어가면 그 캔버스 toDataUrl 이 에러가 나서... 캔버스 캡쳐 기능 작동에서 에러가 
    나기 땜시롱...  

** 만약 XMLHttpRequest 로 업로드가 성공한다면... 파일 등록 아이디등 결과값 받는것은 xhr.addEventListener(....) 로 콜백 
    펑션을 지정해서 그쪽에서 값을 받을수 있는거 같다.

    http://www.matlus.com/html5-file-upload-with-progress/
  

** 일단은 파일 업로드 기능이 크로스 도메인에 되게 해서 쓰고 있는데, 소스를 고친거는 아니고 

    크롬 실행할때  chrome.exe --disable-web-security   요렇게 되게 하고 있음.

 

이래저래 하는 시도하는 과정에서 참고한 url 을 붙여둔다.  
( 파일업로드가 아닌 ajax cross-domain 의 경우에는 PASS가 될수도 있을거 같다...  예전엔 확실히 되었는데 브라우저, jquery 업그레이드 등으로 요샌 안될수도 있을것이다. )

http://stackoverflow.com/questions/5157361/jquery-equivalent-to-xmlhttprequests-upload

http://stackoverflow.com/questions/18310394/no-access-control-allow-origin-node-apache-port-issue

http://blog.naver.com/sef16/70169387710

http://mathiasbynens.be/notes/xhr-responsetype-json

http://teragoon.wordpress.com/2013/03/29/426/

http://www.matlus.com/html5-file-upload-with-progress/

 

 

=================================

=================================

=================================

 

 

 

출처: http://unikys.tistory.com/233

[Javascript] AJAX (XMLHttpRequest)로 비동기적으로 파일 업로드하기

Programming Tips/Web Programming 2012.10.05 12:58

[자바스크립트] Uploading file with AJAX (XMLHttpRequest)

 

 

: 지금까지 웹 언어들을 사용할 때 파일을 업로드 할때에는 form과 input type="file"을 이용해왔다.

 

<form enctype="multipart/form-data" action="_URL" method="POST" id="upload_form">

      <input type="hidden" name="MAX_FILE_SIZE" value="300000" />

      <input type="file" id="upload_file" />

      <input type="submit" value="파일 전송" />

</form>

 

 

: 위의 구현은 php.net에 있는 내용을 가져온 것으로 <form method="post"> 태그 안에 단순히 form을 submit하는 것만으로 쉽게 구현이 가능했지만, 이러한 방법은 페이지 새로 고침(refresh) 현상을 유도하게 되고 이는 사용자 경험에 있어서 마이너스가 된다. (비동기를 적용하게 되는 것은 클라이언트 쪽이니까 서버측 구현은 일단 무시하자.)

 

: 하지만 이러한 방법이 이제 어려워지는 가장 큰 이유는 바로 HTML5를 적용한 웹페이지들이 많아지면서 일 것이다. HTML5에서 HTML은 MVC 모델에서 철저하게 V에 해당하며 html 파일 안에 다른 웹 언어를 넣는 것이 지양되고 있다.

 

: 그렇다면 순수하게 HTML과 Javascript를 이용해서 파일을 업로드하는 방법이 있어야하는데 XMLHttpRequest를 이용하면 이를 쉽게 할 수 있다.

 

: 방법은 간단하게 XMLHttpRequest의 send() 함수에서 인자로 FormData를 넘겨주면 된다. FormData를 구성하는 방법은 위의 소스와 같이 html로 되어있는 경우는 아래와 같이 구현하면 된다.

 

<script>

    var form = document.getElementById("upload_form");

    var formData = new FormData(form);

 

    var xhr = new XMLHttpRequest();

    xhr.open("POST" , "/upload/request_url" , true);

    xhr.send(formData);

</script>

 

: 이렇게 하면 upload_form의 id를 가진 form을 가져와서 해당하는 form의 정보들을 이용해서 FormData 클래스를 만들고, 이를 XMLHttpRequest에서 요청하는 url로 POST method로 첨부를 하게 된다.

 

: 만약에 하나의 커다란 form 전체가 아니라 파일 하나를 첨부하고 싶다면 아래와 같이 하면 된다.

 

<script>

    var fileInput = document.getElementById("upload_file");

    var file = fileInput.files[0];

    var formData = new FormData();

    formData.append("upload_file" , file);

 

    var xhr = new XMLHttpRequest();

    xhr.open("POST" , "/upload/request_url" , true);

    xhr.send(formData);

</script>

 

: 이렇게 하면 url로 건내주는 데이터의 양이 최소화 되므로, 자그마한 트래픽 최적화를 원한다면 이렇게 하는 것도 좋을 것이다.

 

 

* 활용 방법

 

: 위의 자바스크립트를 기존의 동작들이나 html과 일관성을 가지고 input type="submit"을 활용하고 싶다면, form의 onsubmit 이벤트에 위의 소스를 넣어서 처리하면 된다.

 

var form = document.getElementById("upload_form");

form.onsubmit = function()

{

    var formData = new FormData(form);

    formData.append('upload_file' , upload_file);

    xhr.open("POST" , form.getAttribute("action") , true);

    xhr.send(formData);

 

    return false;    //중요! false를 리턴해야 버튼으로 인한 submit이 안된다.

}

 

 : XMLHttpRequest를 이용해서 progress바를 표시하여 현재 진행 상황 등을 보여주는데 응용할수도 있다. 아래와 같이 간단하게 진행 상태를 확인할 수 있다.

 

xhr.onprogress = function(evt){

    someDiv.innerHTML = evt.loaded + "/" + evt.total;

};

 

: 이를 이용한 응용은 다음에 다룰 수 있으면 다뤄볼 것이다. HTML5의 slider나 canvas를 이용하면 그래픽적으로 파일 업로드/다운로드 진행바를 구현하는 것도 아주 쉬운일이다.

 

끝.

 

 

=================================

=================================

=================================

 

 

 

출처: http://micropilot.tistory.com/2217

 

 

HTML5에서 제시하는 Javascript FileSystem API를 사용하면 웹페이지에서도 로컬 시스템의 파일 시스템에 접근하여 파일을 읽고 쓰는 일이 가능하다.

물론 파일을 생성하는 것과 파일이나 디렉토리를 이동하면서 어떤 작업을 수행하는 것도 가능해졌다.

FileSystem API는 SandBox 보안모델이 적용되어 외부로부터 로컬 시스템에 가해지는 보안상 피해를 최소화하는 범위 내에서 작동하도록 설계되었다.

FileSystem API를 통하여 생성되는 파일은 로컬 시스템에서 참조할 수 없는 영역에 생성되고 지정한 파일 이름으로 파일이 생성되는 것도 아니다. 그러므로 FileSystem API에서 사용하는 SandBox 전용 저장소는 웹브라우저 내부에서만 읽고 쓸 수 있는 저장소이므로 로컬 시스템과 관련이 없는 저장소이기 때문에 일반 사용자가 로컬 시스템에서 참조할 수 있는 영역이 아니다. 또한 보안상 위험할 수 있는 실행파일 등은 저장할 수 없도록 스펙에 정의되어 있다

 

참고원문: http://www.html5rocks.com/en/tutorials/file/filesystem/

 

HTML5가 지원하는 Javascript FileSystem API 는 다음과 같이 분류된다

  • Reading and manipulating files: File/Blob, FileList, FileReader
  • Creating and writing: Blob(), FileWriter
  • Directories and file system access: DirectoryReader,FileEntry/DirectoryEntry, LocalFileSystem

FileSystem API는 현재 Google Chrome 브라우저에서 지원하고 있으며 아래의 코드는 모두 Google Chrome 브라우저에서 테스트를 거쳤다

 

학습목표: 현재 로컬 시스템에 있는 파일을 로드하여 내용을 화면에 출력하고, 만약 특정 이름의 파일이 로컬 시스템의 특정 위치에서 발견되지 않는다면 서버측에 있는 동일 이름의 파일을 가져와서 로컬 시스템에 저장한다.

 

현재 Javascript가 실행되는 OS의 종류 알아내기

var OSName="Unknown OS"; if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows"; if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS"; if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX"; if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux"; if (navigator.appVersion.indexOf("Android")!=-1 OSName="Android"; document.write('Your OS: '+OSName);

 

Yout OSName = Windows

 

현재의 브라우저가 FileSystem API를 지원하는지 확인하고 로컬시스템에 파일의 생성, 쓰기, 읽기, 삭제를 테스트하는 코드

<script>

/*  실행중 오류 발생시 호출될 콜백함수 */

function errorCallback(error) {

  var message = '';

 

  switch (error.message) {

    case FileError.SECURITY_ERR:

      message = 'Security Error';

      break;

    case FileError.NOT_FOUND_ERR:

      message = 'Not Found Error';

      break;

    case FileError.QUOTA_EXCEEDED_ERR:

      message = 'Quota Exceeded Error';

      break;

    case FileError.INVALID_MODIFICATION_ERR:

      message = 'Invalid Modification Error';

      break;

    case FileError.INVALID_STATE_ERR:

      message = 'Invalid State Error';

      break;

    default:

      message = 'Unknown Error';

      break;

  }

  //console.log(message);

  printMsg(message);

}

 

var filesystem = null;

 

/* 현재 브라우저가 FileSystem API를 지원하는지 확인하는 함수 */

function checkFileSystem() {

    // Handle vendor prefixes.  requestFileSystem is prefixed in Google Chrome and Opera.

    window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

    if(window.requestFileSystem) {

        //console.log("FileSystem을 지원하는 브라우저입니다");

        printMsg("FileSystem을 지원하는 브라우저입니다");

    }

    else {

       //console.log("FileSystem을 지원하지 않는 브라우저입니다");

       printMsg("FileSystem을 지원하지 않는 브라우저입니다");

    }

}

 

/* FileSystem API 가 임시저장소 기능을 지원하는지 확인 */

function checkTempFileSystem() {

window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

 

// Request a FileSystem (임시 저장소, 브라우저가 임의로 삭제 가능한 저장소 요청)

window.requestFileSystem(window.TEMPORARY, 1024 * 1024, 

  function(filesystem) {

   //console.log("임시저장소 기능을 지원하는 브라우저입니다");

   printMsg("임시저장소 기능을 지원하는 브라우저입니다");

  },

  function(error) {

   //console.log("임시저장소 기능을 지원하지 않는 브라우저입니다");

   printMsg("임시저장소 기능을 지원하지 않는 브라우저입니다");

  }

);

}

 

/* FileSystem API 가 영구저장소 기능을 지원하는지 확인 */

function checkPerFileSystem() {

// 브라우저가 임의로 삭제하지 않는 영구 저장소 요청의 경우

window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

navigator.webkitPersistentStorage.requestQuota(

1024 * 1024 * 10,

function(grantedSize) {

 

// Request a file system with the new size.

window.requestFileSystem(window.PERSISTENT, grantedSize, 

function(fs) {

filesystem = fs;

//console.log("대용량 영구 저장소 요청성공");

printMsg("대용량 영구 저장소 요청성공");

 // Do something with your new (larger) fs

//console.log('Opened file system: ' + fs.name);

//printMsg('Opened file system: ' + fs.name);

 },

 errorCallback

 );

},

errorCallback

);

}

 

/*  로컬 시스템상에 파일을 생성함 */

function createLocalFile() {

    filesystem.root.getFile('log.txt', {create: true, exclusive: true}, 

       function(fileEntry) {

          //console.log("생성된 파일의 절대경로", fileEntry.fullPath);

          printMsg("생성된 파일의 절대경로" + fileEntry.fullPath);

       }, 

   errorCallback 

);

}

 

/* 로컬 시스템상의 파일에 쓰기 */

function writeLocalFile() {

filesystem.root.getFile('log.txt', {create: true, exclusive: false}, 

   function(fileEntry) {

 // console.log("파일의 절대경로", fileEntry.fullPath);

 printMsg("파일의 절대경로", fileEntry.fullPath);

  // Create a FileWriter object for our FileEntry (log.txt).

  fileEntry.createWriter(function(fileWriter) {

  //console.log("FileWriter 생성 성공");

  printMsg("FileWriter 생성 성공");

  fileWriter.onwriteend = function(e) { //파일에 쓰기 성공 이벤트

//console.log('파일쓰기 성공.');

printMsg('파일쓰기 성공.');

  };

 

  fileWriter.onerror = function(e) { //파일에 쓰기 실패 이벤트

//console.log('파일쓰기 실패: ' + e.toString());

printMsg('파일쓰기 실패: ' + e.toString());

  };

 

  var blob = new Blob(['사랑합니다 and\n감사합니다'], {type: 'text/plain'}, 'utf-8');

  fileWriter.write(blob);

  //fileWriter.seek(0);

  }, errorCallback); // fileWriter생성 성공/실패 이벤트 끝

 

   }, errorCallback ); // getFile() 성공/실패 이벤트 끝

}

 

/* 로컬 시스템상의 파일로부터 읽어오기 */

function readLocalFile() {

// 파일 읽기

filesystem.root.getFile('log.txt', {}, function(fileEntry) {

//console.log("파일 읽기 위해 열기 성공");

printMsg("파일 읽기 위해 열기 성공");

// Get a File object representing the file,

// then use FileReader to read its contents.

fileEntry.file( function(file) { //파일 오브젝트를 구함, 성공 이벤트

//console.log("파일 오브젝트 구하기 성공");

printMsg("파일 오브젝트 구하기 성공");

var reader = new FileReader();

 

reader.onloadend = function(e) {

//console.log("파일읽기 내용:"+this.result );

printMsg("파일읽기 내용:"+this.result );

};

 

reader.readAsText(file, 'utf-8');

 

}, errorCallback); // 파일 오브젝트 얻기(file()) 성공/실패 이벤트 끝

}, errorCallback); // getFile 성공/실패 이벤트 끝

// 파일 읽기 끝

}

 

/* 로컬 시스템상의 파일삭제 */

function removeLocalFile() {

filesystem.root.getFile('log.txt', {create: false, exclusive: false}, 

function(fileEntry) {

//console.log("삭제할 파일의 절대경로", fileEntry.fullPath);

printMsg("삭제할 파일의 절대경로", fileEntry.fullPath);

fileEntry.remove( function() { //삭제성공 이벤트

//console.log('파일삭제 성공');

printMsg('파일삭제 성공');

}, errorCallback );

}, errorCallback 

);

}

 

/* 위의 함수들이 실행될 때 메시지를 화면에 출력하는 함수 */

function printMsg(str) {

    document.getElementById("div1").innerHTML = "";

    document.getElementById("div1").innerHTML = str;

}

 

</script><br />

 

<div id="div1" style="border:1px solid blue; width:100%; height:2em;">  </div>

 

 

PC나 Android 폰의 Chrome 브라우저에서 아래의 버튼을 누르면 위의 내용을 테스트할 수 있다

 

 

 

=================================

=================================

=================================

 

 

 

반응형

 

728x90

 

 

 

 

 

 

출처: http://www.html5rocks.com/en/tutorials/file/filesystem/

 

Introduction

I've always thought it would be handy if web applications could read and write files and directories. As we move from offline to online, applications are becoming more complex and the lack of file system APIs has been a hindrance for moving the web forward. Storing or interacting with binary data shouldn't be limited to the desktop. Thankfully, it no longer is thanks to the FileSystem API. With the FileSystem API, a web app can create, read, navigate, and write to a sandboxed section of the user's local file system.

The API is broken up into various themes:

  • Reading and manipulating files: File/Blob, FileList, FileReader
  • Creating and writing: Blob(), FileWriter
  • Directories and file system access: DirectoryReader,FileEntry/DirectoryEntry, LocalFileSystem

Browser support & storage limitations

At the time of writing this article, Google Chrome has the only working implementation of the FileSystem API. A dedicated browser UI does not yet exist for file/quota management. To store data on the user's system, may require your app to request quota. However, for testing, Chrome can be run with the --unlimited-quota-for-files flag. Furthermore, if you're building an app or extension for the Chrome Web Store, the unlimitedStorage manifest filepermission can be used in place of requesting quota. Eventually, users will receive a permission dialog to grant, deny, or increase storage for an app.

You may need the --allow-file-access-from-files flag if you're debugging your app from file://. Not using these flags will result in a SECURITY_ERR orQUOTA_EXCEEDED_ERR FileError.

Requesting a file system

A web app can request access to a sandboxed file system by callingwindow.requestFileSystem():

// Note: The file system has been prefixed as of Google Chrome 12:
window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;

window.requestFileSystem(type, size, successCallback, opt_errorCallback)

 

type

Whether the file storage should be persistent. Possible values arewindow.TEMPORARY or window.PERSISTENT. Data stored usingTEMPORARY can be removed at the browser's discretion (for example if more space is needed). PERSISTENT storage cannot be cleared unless explicitly authorized by the user or the app and requires the user to grant quota to your app. See requesting quota.

size

Size (in bytes) the app will require for storage.successCallbackCallback that is invoked on successful request of a file system. Its argument is a FileSystem object.

 

opt_errorCallback

Optional callback for handling errors or when the request to obtain the file system is denied. Its argument is a FileError object.

 

If you're calling requestFileSystem() for the first time, new storage is created for your app. It's important to remember that this file system is sandboxed, meaning one web app cannot access another app's files. This also means you cannot read/write files to an arbitrary folder on the user's hard drive (for example My Pictures, My Documents, etc.).

Example usage:

function onInitFs(fs) {
  console.log('Opened file system: ' + fs.name);
}

window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);

 

The FileSystem specification also defines a synchronous API,LocalFileSystemSync interface that is intended to be used in Web Workers. However, this tutorial will not cover the synchronous API.

Throughout the remainder of this document, we'll use the same handler for processing errors from the asynchronous calls:

function errorHandler(e) {
  var msg = '';

  switch (e.code) {
    case FileError.QUOTA_EXCEEDED_ERR:
      msg = 'QUOTA_EXCEEDED_ERR';
      break;
    case FileError.NOT_FOUND_ERR:
      msg = 'NOT_FOUND_ERR';
      break;
    case FileError.SECURITY_ERR:
      msg = 'SECURITY_ERR';
      break;
    case FileError.INVALID_MODIFICATION_ERR:
      msg = 'INVALID_MODIFICATION_ERR';
      break;
    case FileError.INVALID_STATE_ERR:
      msg = 'INVALID_STATE_ERR';
      break;
    default:
      msg = 'Unknown Error';
      break;
  };

  console.log('Error: ' + msg);
}

 

Granted, this error callback is very generic, but you get the idea. You'll want to provide human-readable messages to users instead.

Requesting storage quota

To use PERSISTENT storage, you must obtain permission from the user to store peristent data. The same restriction doesn't apply to TEMPORARY storage because the browser may choose to evict temporarily stored data at its discretion.

To use PERSISTENT storage with the FileSystem API, Chrome exposes a new API under window.webkitStorageInfo to request storage:

window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
  window.requestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, function(e) {
  console.log('Error', e);
});

Once the user has granted permission, there's no need to call requestQuota() in the future (unless you wish to increase your app's quota). Subsequent calls for equal or lesser quota are a noop.

There is also an API to query an origin's current quota usage and allocation:window.webkitStorageInfo.queryUsageAndQuota()

Working with files

Files in the sandboxed environment are represented by the FileEntry interface. A FileEntry contains the types of properties (name, isFile, ...) and methods (remove,moveTo, copyTo, ...) that you'd expect from a standard file system.

Properties and methods of FileEntry:

 

fileEntry.isFile === true
fileEntry.isDirectory === false
fileEntry.name
fileEntry.fullPath
...

fileEntry.getMetadata(successCallback, opt_errorCallback);
fileEntry.remove(successCallback, opt_errorCallback);
fileEntry.moveTo(dirEntry, opt_newName, opt_successCallback, opt_errorCallback);
fileEntry.copyTo(dirEntry, opt_newName, opt_successCallback, opt_errorCallback);
fileEntry.getParent(successCallback, opt_errorCallback);
fileEntry.toURL(opt_mimeType);

fileEntry.file(successCallback, opt_errorCallback);
fileEntry.createWriter(successCallback, opt_errorCallback);
...

 

To better understand FileEntry, the rest of this section contains a bunch of recipes for performing common tasks.

Creating a file

You can look up or create a file with the file system's getFile() method, a method of the DirectoryEntry interface. After requesting a file system, the success callback is passed a FileSystem object that contains a DirectoryEntry(fs.root) pointing to the root of the app's file system.

The following code creates an empty file called "log.txt" in the root of the app's file system:

 

function onInitFs(fs) {

  fs.root.getFile('log.txt', {create: true, exclusive: true}, function(fileEntry) {

    // fileEntry.isFile === true
    // fileEntry.name == 'log.txt'
    // fileEntry.fullPath == '/log.txt'

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

 

Once the file system has been requested, the success handler is passed aFileSystem object. Inside the callback, we can call fs.root.getFile() with the name of the file to create. You can pass an absolute or relative path, but it must be valid. For instance, it is an error to attempt to create a file whose immediate parent does not exist. The second argument to getFile() is an object literal describing the function's behavior if the file does not exist. In this example, create: truecreates the file if it doesn't exist and throws an error if it does (exclusive: true). Otherwise (if create: false), the file is simply fetched and returned. In either case, the file contents are not overwritten because we're just obtaining a reference entry to the file in question.

Reading a file by name

The following code retrieves the file called "log.txt", its contents are read using theFileReader API and appended to a new <textarea> on the page. If log.txt doesn't exist, an error is thrown.

function onInitFs(fs) {

  fs.root.getFile('log.txt', {}, function(fileEntry) {

    // Get a File object representing the file,
    // then use FileReader to read its contents.
    fileEntry.file(function(file) {
       var reader = new FileReader();

       reader.onloadend = function(e) {
         var txtArea = document.createElement('textarea');
         txtArea.value = this.result;
         document.body.appendChild(txtArea);
       };

       reader.readAsText(file);
    }, errorHandler);

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Writing to a file

The following code creates an empty file called "log.txt" (if it doesn't exist) and fills it with the text 'Lorem Ipsum'.

function onInitFs(fs) {

  fs.root.getFile('log.txt', {create: true}, function(fileEntry) {

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function(fileWriter) {

      fileWriter.onwriteend = function(e) {
        console.log('Write completed.');
      };

      fileWriter.onerror = function(e) {
        console.log('Write failed: ' + e.toString());
      };

      // Create a new Blob and write it to log.txt.
      var blob = new Blob(['Lorem Ipsum'], {type: 'text/plain'});

      fileWriter.write(blob);

    }, errorHandler);

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

This time, we call the FileEntry's createWriter() method to obtain a FileWriterobject. Inside the success callback, event handlers are set up for error andwriteend events. The text data is written to the file by creating a blob, appending text to it, and passing the blob to FileWriter.write().

Appending data to a file

The following code appends the text 'Hello World' to the end of our log file. An error is thrown if the file does not exist.

 

function onInitFs(fs) {

  fs.root.getFile('log.txt', {create: false}, function(fileEntry) {

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function(fileWriter) {

      fileWriter.seek(fileWriter.length); // Start write position at EOF.

      // Create a new Blob and write it to log.txt.
      var blob = new Blob(['Hello World'], {type: 'text/plain'});

      fileWriter.write(blob);

    }, errorHandler);

  }, errorHandler);

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

 

Duplicating user-selected files

The following code allows a user to select multiple files using <input type="file" multiple /> and creates copies of those files in the app's sandboxed file system.

<input type="file" id="myfile" multiple />
document.querySelector('#myfile').onchange = function(e) {
  var files = this.files;

  window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
    // Duplicate each file the user selected to the app's fs.
    for (var i = 0, file; file = files[i]; ++i) {

      // Capture current iteration's file in local scope for the getFile() callback.
      (function(f) {
        fs.root.getFile(f.name, {create: true, exclusive: true}, function(fileEntry) {
          fileEntry.createWriter(function(fileWriter) {
            fileWriter.write(f); // Note: write() can take a File or Blob object.
          }, errorHandler);
        }, errorHandler);
      })(file);

    }
  }, errorHandler);

};

Although we've used an input for the file import, one could easily leverage HTML5 Drag and Drop to achieve the same objective.

As noted in the comment, FileWriter.write() can accept a Blob or File. This is because File inherits from Blob. Therefore, all file objects are blobs.

Removing a file

The following code deletes the file 'log.txt'.

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getFile('log.txt', {create: false}, function(fileEntry) {

    fileEntry.remove(function() {
      console.log('File removed.');
    }, errorHandler);

  }, errorHandler);
}, errorHandler);

Working with directories

Directories in the sandbox are represented by the DirectoryEntry interface, which shares most of FileEntry's properties (they inherit from a common Entryinterface). However, DirectoryEntry has additional methods for manipulating directories.

Properties and methods of DirectoryEntry:

dirEntry.isDirectory === true
// See the section on FileEntry for other inherited properties/methods.
...

var dirReader = dirEntry.createReader();
dirEntry.getFile(path, opt_flags, opt_successCallback, opt_errorCallback);
dirEntry.getDirectory(path, opt_flags, opt_successCallback, opt_errorCallback);
dirEntry.removeRecursively(successCallback, opt_errorCallback);
...

Creating directories

Use the getDirectory() method of DirectoryEntry to read or create directories. You can pass either a name or path as the directory to look up or create.

For example, the following code creates a directory named "MyPictures" in the root directory:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getDirectory('MyPictures', {create: true}, function(dirEntry) {
    ...
  }, errorHandler);
}, errorHandler);

Subdirectories

Creating a subdirectory is exactly the same as creating any other directory. However, the API throws an error if you attempt to create a directory whose immediate parent does not exist. The solution is to create each directory sequentially, which is rather tricky to do with an asynchronous API.

The following code creates a new hierarchy (music/genres/jazz) in the root of the app's FileSystem by recursively adding each subdirectory after its parent folder has been created.

 

var path = 'music/genres/jazz/';

function createDir(rootDirEntry, folders) {
  // Throw out './' or '/' and move on to prevent something like '/foo/.//bar'.
  if (folders[0] == '.' || folders[0] == '') {
    folders = folders.slice(1);
  }
  rootDirEntry.getDirectory(folders[0], {create: true}, function(dirEntry) {
    // Recursively add the new subfolder (if we still have another to create).
    if (folders.length) {
      createDir(dirEntry, folders.slice(1));
    }
  }, errorHandler);
};

function onInitFs(fs) {
  createDir(fs.root, path.split('/')); // fs.root is a DirectoryEntry.
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

 

Now that "music/genres/jazz" is in place, we can pass its full path togetDirectory() and create new subfolders or files under it. For example:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getFile('/music/genres/jazz/song.mp3', {create: true}, function(fileEntry) {
    ...
  }, errorHandler);
}, errorHandler);

Reading a directory's contents

To read the contents of a directory, create a DirectoryReader and call itsreadEntries() method. There is no guarantee that all of a directory's entries will be returned in a single call to readEntries(). That means you need to keep calling DirectoryReader.readEntries() until no more results are returned. The following is code that demonstrates this:

<ul id="filelist"></ul>
function toArray(list) {
  return Array.prototype.slice.call(list || [], 0);
}

function listResults(entries) {
  // Document fragments can improve performance since they're only appended
  // to the DOM once. Only one browser reflow occurs.
  var fragment = document.createDocumentFragment();

  entries.forEach(function(entry, i) {
    var img = entry.isDirectory ? '<img src="folder-icon.gif">' :
                                  '<img src="file-icon.gif">';
    var li = document.createElement('li');
    li.innerHTML = [img, '<span>', entry.name, '</span>'].join('');
    fragment.appendChild(li);
  });

  document.querySelector('#filelist').appendChild(fragment);
}

function onInitFs(fs) {

  var dirReader = fs.root.createReader();
  var entries = [];

  // Call the reader.readEntries() until no more results are returned.
  var readEntries = function() {
     dirReader.readEntries (function(results) {
      if (!results.length) {
        listResults(entries.sort());
      } else {
        entries = entries.concat(toArray(results));
        readEntries();
      }
    }, errorHandler);
  };

  readEntries(); // Start reading dirs.

}

window.requestFileSystem(window.TEMPORARY, 1024*1024, onInitFs, errorHandler);

Removing a directory

The DirectoryEntry.remove() method behaves just like FileEntry's. The difference: attempting to delete a non-empty directory results in an error.

The following removes the empty directory "jazz" from "/music/genres/":

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getDirectory('music/genres/jazz', {}, function(dirEntry) {

    dirEntry.remove(function() {
      console.log('Directory removed.');
    }, errorHandler);

  }, errorHandler);
}, errorHandler);

 

Recursively removing a directory

If you have a pesky directory that contains entries, removeRecursively() is your friend. It deletes the directory and its contents, recursively.

The following code recursively removes the directory "music" and all the files and directories that it contains:

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  fs.root.getDirectory('/misc/../music', {}, function(dirEntry) {

    dirEntry.removeRecursively(function() {
      console.log('Directory removed.');
    }, errorHandler);

  }, errorHandler);
}, errorHandler);

 

Copying, renaming, and moving

FileEntry and DirectoryEntry share common operations.

Copying an entry

Both FileEntry and DirectoryEntry have a copyTo() for duplicating existing entries. This method automatically does a recursive copy on folders.

The following code example copies the file "me.png" from one directory to another:

function copy(cwd, src, dest) {
  cwd.getFile(src, {}, function(fileEntry) {

    cwd.getDirectory(dest, {}, function(dirEntry) {
      fileEntry.copyTo(dirEntry);
    }, errorHandler);

  }, errorHandler);
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  copy(fs.root, '/folder1/me.png', 'folder2/mypics/');
}, errorHandler);

 

Moving or renaming an entry

The moveTo() method present in FileEntry and DirectoryEntry allows you to move or rename a file or directory. Its first argument is the parent directory to move the file under, and its second is an optional new name for the file. If a new name isn't provided, the file's original name is used.

The following example renames "me.png" to "you.png", but does not move the file:

function rename(cwd, src, newName) {
  cwd.getFile(src, {}, function(fileEntry) {
    fileEntry.moveTo(cwd, newName);
  }, errorHandler);
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  rename(fs.root, 'me.png', 'you.png');
}, errorHandler);

 

The following example moves "me.png" (located in the root directory) to a folder named "newfolder".

function move(src, dirName) {
  fs.root.getFile(src, {}, function(fileEntry) {

    fs.root.getDirectory(dirName, {}, function(dirEntry) {
      fileEntry.moveTo(dirEntry);
    }, errorHandler);

  }, errorHandler);
}

window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
  move('/me.png', 'newfolder/');
}, errorHandler);

 

filesystem: URLs

The FileSystem API exposes a new URL scheme, filesystem:, that can be used to fill src or href attributes. For example, if you wanted to display an image and have its fileEntry, calling toURL() would give you the file's filesystem: URL:

var img = document.createElement('img');
img.src = fileEntry.toURL(); // filesystem:http://example.com/temporary/myfile.png
document.body.appendChild(img);

 

Alternatively, if you already have a filesystem: URL,resolveLocalFileSystemURL() will get you back the fileEntry:

window.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL ||
                                   window.webkitResolveLocalFileSystemURL;

var url = 'filesystem:http://example.com/temporary/myfile.png';
window.resolveLocalFileSystemURL(url, function(fileEntry) {
  ...
});

Putting it all together

Basic example

This demo lists the files/folders in the filesystem.

 

 

=================================

=================================

=================================

 

 

 

출처: http://windbear.tistory.com/4

 

[HTML5 - File Access] FILE API 를 이용해 Local File 가져오기.

HTML5 2012.03.15 17:42 바람난곰


File API 는 웹 어플리케이션에서 로컬 파일에 접근할 수 있게 해주는 Javascript API이다.
File API에 관련된 스펙은 아래와 같이 3가지가 진행되고 있다.

1. File API 
2. File API : Write 
3. File API : Directories and System 

아직 진행중이고 구현된 브라우저도 제한적이기 때문에 테스트를 위해서 최신 크롬 브라우저를 이용할 것을 강추한다.

##브라우저 지원사항 확인하기##
File API & FileReader API
Filesystem & FileWriter API


Step 1. HTML        
     <input type="file" id="inputFile" multiple="multiple"/>


먼저 type이 file인 input tag를 생성한다.
input tag가 type이 file일 경우, 자동으로 탐색기와 연결된 버튼을 생성해준다.
탐색기를 열어서 파일을 선택하면 해당 파일들의 정보를 가지고 있는 FIleList를 생성해준다.
파일을 탐색기에서 선택할 때 다수를 선택하게 할려면 multiple 속성을 주고, 한개 씩만 선택하게 할려면 빼면 된다.
      

input tag 에서 파일을 선택하게 되면 FileList 객체가 내부적으로 생성이된다. 
FileList는 File객체의 배열이다. FileList에서 File의 접근은 직접 접근외에 별다는 메소는드는 제공하지 않는다. 

아래는 스펙에서 가져온 인터페이스 정보이다. 

interface FileList {
 
    getter File? item(unsigned long index);
 
    readonly attribute unsigned long length;
 
};
 
 
 
interface File : Blob {
 
    readonly attribute DOMString name;
 
    readonly attribute Date lastModifiedDate;
 
};


Step 2. Javascript
      
FileList에서는 File을 찾는 것과 list의 사이즈를 제공하며, File에서는 이름과 마지막 수정 일자를 제공하는 것을 알 수가 있다. 
추가적으로 스펙에는 나와있지 않지만 크롬 브라우저에서는 파일 사이즈도 알 수가 있다.

document.getElementById("inputFile").onchange=function(){
 
    var fileList=this.files; //input tag의 타입이 file일 경우 내부적으로 files라는 FileList 객체를 자동으로 생성합니다.
 
    var fileListSize=fileList.length;
 
    
 
    document.getElementById("fileListLength").setAttribute("value", fileListSize);
 
    var strOption='';
 
    for(var i=0; i<fileListSize; i++){
 
        var file=fileList[i];
 
        var fileName=file.name;
 
        var fileLastModifiedDate=file.lastModifiedDate;
 
        var fileSize=file.fileSize;
 
        
 
        strOption+='<option>'+fileName+'('+fileSize+' byte) - '+fileLastModifiedDate+'</option>';
 
    }
 
    document.getElementById("fileList").innerHTML=strOption;
 
}; 


onchange 이벤트가 일어날 때 자신이 선택한 FileList를 가지고 와서 Select box에 파일 명과 사이즈를 보여주는 함수이다.

 

 

=================================

=================================

=================================

 

 

 

 

출처 : Habony`s phP
http://habony.tistory.com/63


php는 POST로 파일 업로드기능을 제공합니다. RFC-1867 호환 브라우저(넷스케이프 네비게이터 3 이상, 마이크로소프트 인터넷 익스플로러 3+패치나 패치 없이 그 이상 버전을 포함)라면 파일 업로드를 받을 수 있는 기능을 제공합니다.

다음 표의 내용을 php.ini에서 조작할 수 있습니다.

 옵션  의미
 file_uploads  업로드 기능을 사용할지를 결정합니다. 기본값 On
 upload_tmp_dir  업로드시 임시 저장 될 디렉토리 경로
 upload_max_filesize  허용하는 최대 파일 크기, 기본값 100M
 max_file_uploads  허용하는 최대 업로드 수, 기본값 100개


파일 업로드 폼은 다음 표처럼 작성하되 폼 안에 enctype="multipart/form-data"값이 있는지 확인하여야 합니다. 그렇지 않으면 업로드 기능은 작동하지 않습니다.

 <form enctype="multipart/form-data" action="send_ok.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    이 파일을 전송합니다: <input name="userfile" type="file" />
    <input type="submit" value="파일 전송" />
 </form>


method는 post로 정의하며, MAX_FILE_SIZE는 php.ini에 지정된 upload_max_filesize 크기 보다 클 수 는 없습니다. 이 필드는 ini에 지정된 파일크기보다 크면 에러를 표시하는 용도로만 사용되어야 합니다.

보통 하나의 파일을 업로드하면 다음 표의 변수($_FILES['파일명']['name'])를 여러개 가지게 됩니다.

 변수명  의미
 name  클라이언트측 원래 이름
 type  "image/gif"와 같은 파일의 mime형식, 그러나 php에서 확인하지 않으므로 이 값을 무시하여야 합니다.
 size  업로드된 파일의 바이트로 표현한 크기
 tmp_name  서버에 저장된 업로드된 파일의 임시 파일 이름
 error  파일 업로드에 대한 에러 코드를 표시


파일 업로드는 다음 예제와 같은 과정으로 작성하면 됩니다.

예제 (ex #1

  <form enctype="multipart/form-data" action="" method="POST"> 
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" /> 
    이 파일을 전송합니다: <input name="userfile" type="file" /> 
    <input type="submit" value="파일 전송" /> 
 </form> 

 <?php 
 
// uploads디렉토리에 파일을 업로드합니다. 
 
$uploaddir './uploads/'
 
$uploadfile $uploaddir basename($_FILES['userfile']['name']); 

 echo 
'<pre>'
 if(
$_POST['MAX_FILE_SIZE'] < $_FILES['userfile']['size']){ 
      echo 
"업로드 파일이 지정된 파일크기보다 큽니다.\n"
 } else { 
     if((
$_FILES['userfile']['error'] > 0) || ($_FILES['userfile']['size'] <= 0)){ 
          echo 
"파일 업로드에 실패하였습니다."
     } else { 
          
// HTTP post로 전송된 것인지 체크합니다. 
          
if(!is_uploaded_file($_FILES['userfile']['tmp_name'])) { 
                echo 
"HTTP로 전송된 파일이 아닙니다."
          } else { 
                
// move_uploaded_file은 임시 저장되어 있는 파일을 ./uploads 디렉토리로 이동합니다. 
                
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { 
                     echo 
"성공적으로 업로드 되었습니다.\n"
                } else { 
                     echo 
"파일 업로드 실패입니다.\n"
                } 
          } 
     } 
 } 

 
print_r($_FILES); 

 
/* 
 결과: 
 성공적으로 업로드 되었습니다. 
 Array 
 ( 
    [userfile] => Array 
        ( 
            [name] => config.sys 
            [type] => text/plain 
            [tmp_name] => /tmp/phpXTtzBW 
            [error] => 0 
            [size] => 10 
        ) 
 ) 
 */ 
 
?> 


파일 업로드가 성공적이면 에러코드는 0을 가집니다. 에러 코드는 다음 표의 상수로 대조해도 됩니다.

 상수명  의미
 UPLOAD_ERR_OK  값: 0; 오류 없이 파일 업로드가 성공했습니다
 UPLOAD_ERR_INI_SIZE 값: 1; 업로드한 파일이 php.ini upload_max_filesize 지시어보다 큽니다
 UPLOAD_ERR_FORM_SIZE  값: 2; 업로드한 파일이 HTML 폼에서 지정한 MAX_FILE_SIZE 보다 큽니다. 
 UPLOAD_ERR_PARTIAL  값: 3; 파일이 일부분만 전송되었습니다
 UPLOAD_ERR_NO_FILE  값: 4; 파일이 전송되지 않았습니다
 UPLOAD_ERR_NO_TMP_DIR  값: 6; 임시 폴더가 없습니다. PHP 4.3.10과 PHP 5.0.3에서 추가.
 UPLOAD_ERR_CANT_WRITE  값: 7; 디스크에 파일 쓰기를 실패했습니다. PHP 5.1.0에서 추가
 UPLOAD_ERR_EXTENSION  값: 8; 확장에 의해 파일 업로드가 중지되었습니다. PHP 5.2.0에서 추가.


파일 이름을 서버에 그대로 저장하는 것도 보안상 상당한 위험이 있으므로 md5로 암호화해서 저장하고, 디비에 원래 이름을 저장하도록 합니다.

예제 (ex #2

   <form enctype="multipart/form-data" action="" method="POST"> 
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" /> 
    이 파일을 전송합니다: <input name="userfile" type="file" /> 
    <input type="submit" value="파일 전송" /> 
 </form> 

 <?php 
 
function file_errmsg($code){ 
     switch(
$code){ 
         case(
UPLOAD_ERR_INI_SIZE): 
         return 
"업로드한 파일이 php.ini upload_max_filesize보다 큽니다."
     case(
UPLOAD_ERR_FORM_SIZE): 
         return 
"업로드한 파일이 MAX_FILE_SIZE 보다 큽니다. "
     case(
UPLOAD_ERR_PARTIAL): 
         return 
"파일이 일부분만 전송되었습니다. 다시 시도해 주십시요."
     case(
UPLOAD_ERR_NO_FILE): 
         return 
"파일이 전송되지 않았습니다."
     case(
UPLOAD_ERR_NO_TMP_DIR): 
         return 
"임시 폴더가 없습니다."
     case(
UPLOAD_ERR_CANT_WRITE): 
         return 
"디스크에 파일 쓰기를 실패했습니다. 다시 시도해 주십시요."
     default: 
         return 
"확장에 의해 파일 업로드가 중지되었습니다."
     } 
 } 

 
// 서버에 저장될 디렉토리이름 
 
$uploaddir './uploads/'
 
// 서버에 저장될 파일이름 
 
$filename basename($_FILES['userfile']['name']); 
 
$md5filename $uploaddir md5("habony_".$filename); 
 
$ext array_pop(explode(".","$filename"); 

 echo 
'<pre>'
 if(
$_FILES['userfile']['error'] === UPLOAD_ERR_OK) { 
      if(
strtolower($ext) == "php") { 
           echo 
"확장자 php파일은 업로드 하실수 없습니다."
      } 
      else if(
$_FILES['userfile']['size'] <= 0){ 
          echo 
"파일 업로드에 실패하였습니다."
      } else { 
          
// HTTP post로 전송된 것인지 체크합니다. 
          
if(!is_uploaded_file($_FILES['userfile']['tmp_name'])) { 
               echo 
"HTTP로 전송된 파일이 아닙니다."
          } else { 
               
// move_uploaded_file은 임시 저장되어 있는 파일을 ./uploads 디렉토리로 이동합니다. 
               
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $md5filename)) { 
                    echo 
"성공적으로 업로드 되었습니다.\n"
               } else { 
                    echo 
"파일 업로드 실패입니다.\n"
               } 
               
mysql_query("insert into $db values  ('','$filename')"); 
          } 
      } 
 } else { 
      echo 
file_errmsg($_FILES['userfile']['error']); 
 } 

 
print_r($_FILES); 

 
/* 
 결과: 
 성공적으로 업로드 되었습니다. 
 Array 
 ( 
    [userfile] => Array 
        ( 
            [name] => config.sys 
            [type] => text/plain 
            [tmp_name] => /tmp/phpXTtzBW 
            [error] => 0 
            [size] => 10 
        ) 
 ) 
 */ 
 
?>



출처 : Habony`s phP
http://habony.tistory.com/63

 

 

=================================

=================================

=================================

 

 

 

출처: http://noritersand.tistory.com/265

 

ajax 파일전송

Script/jQuery 2014.02.17 14:25

참고 문서

http://hmkcode.com/spring-mvc-upload-file-ajax-jquery-formdata/

http://hacks.mozilla.or.kr/2010/05/firefox-4-formdata

 

브라우저 호환

IE9와 그 이하에서는 FormData 객체 생성이 안될 수도 있음악의축마소

 

<body>
    <form id="submitForm" enctype="multipart/form-data">
         <input name="attachFile" id="attachFile" type="file">
         <button type="button" id="submitBtn">upload</button>
    </form>
</body>
Colored by Color Scripter

 

<script>
    $(document).ready(function() {
        $('#submitBtn').click(function() {
            var data = new FormData();
            $.each($('#attachFile')[0].files, function(i, file) {          
                data.append('file-' + i, file);
            });
             
            $.ajax({
                url: '/upload.action',
                type: "post",
                dataType: "text",
                data: data,
                // cache: false,
                processData: false,
                contentType: false,
                success: function(data, textStatus, jqXHR) {
                    alert(data);
                }, error: function(jqXHR, textStatus, errorThrown) {}
            });
        });
    });
</script>
Colored by Color Scripter

 

첨부된 파일을 multipart/form-data 형식으로 처리하기 위해 FormData 객체를 이용했다.

FormData는 객체는 append(key, value) 메서드 하나만 있는 객체로 XMLHttpRequest를 통해 파일을 전송할 수 있게 한다.

 

response example

 

@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public String upload(MultipartHttpServletRequest req, 
    HttpServletResponse res) {


    Iterator<String> itr =  request.getFileNames();
    MultipartFile mpf = request.getFile(itr.next());
    String originFileName = mpf.getOriginalFilename();




    // ... 생략


     
    return "success";
}
Colored by Color Scripter

 

 

'Script > jQuery' 카테고리의 다른 글

JQeury.extend(), 플러그인 만들기  (0)jqGrid  (0)ajax 파일전송  (7)<input type="file"> 파일첨부 입력폼 초기화  (0)jQuery 객체를 동등비교하려면?  (0)레이어 팝업 후 화면 중앙에 배치  (0)

2015.04.15
2014.02.19
2014.02.17
2014.02.05
2014.01.17
2014.01.09

Posted by 놀이터흙이제맛

jQuery

트랙백 0댓글 7개가 달렸습니다

트랙백 주소 :: http://noritersand.tistory.com/trackback/265  

  1.  따라 해봤는데 2015.01.15 12:05      
    (시무룩)
  2.  놀이터흙이제맛 2015.01.23 17:58    
  3. 안되네요 .....
  4. 박재호 2015.03.16 23:10      
    어머낫 스에상에나!!
    ...수정했습니다
  5.  놀이터흙이제맛 2015.03.19 15:14    
  6. $.each($('#inpt_attachFile')[0].files, function(i, file) {<<
    이부분 #input_attachFile 이아니라 attachFile아닙니까?
  7.  2015.04.27 23:45       MultipartRequest의 getFileName()을 통해서 알 수 있어요.

    http://noritersand.tistory.com/132
    위 글에 com.oreilly.servlet.MultipartRequest 사용 예가 간단하게 기술되어 있습니다.

    스프링의 MultipartHttpServletRequest를 사용하시려면 아래 링크를 참고하세요!
    http://hmkcode.com/spring-mvc-upload-file-ajax-jquery-formdata/
    •  2015.04.28 19:39    
    • 감사합니다 ^^
  8.  놀이터흙이제맛 2015.04.28 03:12    
  9. 그 보냈을때 server 쪽에서 파일명은 어떻게 알수 있을까요?

 

=================================

=================================

=================================

 

 

*관련링크

- https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

반응형


관련글 더보기

댓글 영역