ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JS] drag&drop 여러 디렉토리(폴더) 및 파일 업로드기능
    공부 2019. 5. 22. 14:43

    js

    FileSystem API

    FileReader API

    FileEntry API

     

     

    nodejs

    formidable

     

     

     

    • 크롬에서 실습시 서버가 세팅되어있지 않은경우 참고

    (설정 귀찮으면 다른브라우저 파이어폭스나 엣지 등을 사용)

     

    서버가 없으면 브라우저에서 file:// 로 로컬파일에 접근하는건데

    크롬의 경우 보안상 api를 이용해 file:// 로 접근하는걸 차단한다

     

    크롬 옵션으로 해제

    --allow-file-access-from-files

     

    참고

    https://developer.mozilla.org/en-US/docs/Web/API/FileError

     

    For security reasons, browsers do not allow you to run your app from file://. In fact, many of the powerful storage APIs (such as File System, BlobBuilder, and FileReader) throw errors if you run the app locally from file://. When you're just testing your app, and you don't want to set up a web server, you can bypass the security restriction on Chrome. Just start Chrome with the --allow-file-access-from-files flag. Use the flag only for testing purposes.

     

     

    크롬 --allow-file-access-from-files 옵션 설정하기

     

    크롬창을 모두 종료한 뒤

     

    chrome 설치위치로 가서 .\chrome.exe -allow-file-access-from-files 입력

    C:\Program Files (x86)\Google\Chrome\Application>.\chrome.exe --allow-file-access-from-files

    또는 경로적고 바로적용

    "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files

    "크롬설치위치" --allow-file-access-from-files

     

    입력시 새창이 뜬다

    크롬창을 모두 닫은상태가 아니었다면 적용이 안된다 닫은후 다시해야함

     

    설정은 크롬창을 모두 닫으면 초기화되어서 다음번에도 또 이렇게 열어야한다

     

     

     

     

     


     

    html

    <div class="container">
    	<div id="fileDropZone" >첨부파일을 이곳으로<br/>드래그하세요.</div>
    </div>

     

    css(적용안해도되지만 시각적으로)

    .container{
      display:flex;
      flex-direction: column;
      align-items : center;
    }
    #fileDropZone{
      border : 2px gray dotted;
      padding : 50px;
      background-color : white;
    }

     


     

    파일은 어떻게 읽나

    드랍한 파일데이터를 어떻게 가져오나

    디렉토리는 어떻게 읽나

     

    알아볼 항목

    File API

    FileReader API

    Blob 데이터

    URL API

    a태그의 download 속성

     

    javascript

     

    drag&drop 이벤트

    dragover : 드래그객체가 해당영역 위에 올라와있을때

    dragleave : 드래그객체가 해당영역에서 벗어남

    drop : 영역에 drop

     

     

    drag&drop 은 DataTransfer 객체 담는다.

    drop이벤트 발생시 event객체에서 dataTransfer로 데이터 객체를 가져온다.

     

    파일의 데이터자체를 읽으려면
    파일을 File 객체로 가져와야한다.

     

    이 File 객체를 FileReader 객체의 api들로 읽는다.

     

     

    • FileReader API

    readAsText(file) : 텍스트로 읽는다

    readAsDataURL(file) : blob형식이 URL로 인코딩하여 읽는다. (값을 src속성에 활용할 수도 있다.)

    주소창에 이 값을 입력하면 브라우저가 알아서해석해서 원래대로 표현한다.

    readAsArrayBuffer(file) : blog형식의 바이너리가 ArrayBuffer 객체로 반환됨

    readAsBinaryString(file) : blob 형식의 바이너리문자열로 반환

     

    발생이벤트에 함수를 붙여 핸들러처리

    onloadstart

    onload : 로드완료

    onloadend 

    onprogress : 진행되는중 (진행률 표시하고싶을때 사용가능)

    onabort

    onerror : 에러

     

    *파일을 chunk로 다루려면 FILE 객체의 slice 메소드 사용

     

     

     

    주요 함수와 반환값들

     

    • event.dataTransfer

    >DataTransfer 객체 반환

     

     

    • dataTransfer.files

    >FileList 객체를 반환

    FileList는 File객체를 갖고있다.

    이 File은 FileReader 객체의 api로 읽으면 파일자체의 데이터를 얻을 수 있다.

    파일만 드랍된 경우 이 객체에서 데이터를 가져오면 된다.

     

     

    • dataTransfer.items

    >DataTransferItemList 객체 반환

    dataTransferItemList은 dataTransferItem을 가진 유사배열(인덱스가 키인 객체)임

    dataTransferItem은 문자열일 수도 파일/디렉토리 일수도있다.

    dataTransferItem.kind 속성은 string이나 file값을 반환한다.

    dataTransferItem.type 속성은 데이터의 type/format 값을 반환한다.

     

    *파일인경우 dataTransferItem은 dataTransferItem.getAsFile() 메소드로 File객체로 변환가능

     

     


     

    드랍한것이 디렉터리일경우 디렉터리탐색을 위해선 Entry 객체로 변환해야함

    파일/디렉토리 구분은 다음 속성을 이용해 판별

    dataTransferItem.isFile => true/false

    dataTransferItem.isDirectory => true/false

     

    • dataTransferItem.webkitGetAsEntry()

    디렉토리면 > FileSystemDirectoryEntry 객체 반환

    파일이면 > FileSystemFileEntry 객체 반환

     

    *fileSystemFileEntry.file(successcallback, [errorcallback]) 메소드로 File 객체를 얻을 수 있다.

    엣지는 Webkit기반이 아니기라 객체가 다르다. WebKitFileEntry와 WebKitDirectoryEntry로 반환

     

    FileSystemEntry의 속성

     

    filesystem

    name : 이름

    isFile : 파일인지 true/false

    isDirectory :디렉토리인지

    fullPath : 드랍된 객체를 기준으로한 경로

     

    FileSystemEntry 의 속성은 모두 ReadOnly이다. 변경할 수 없다.

    https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry

     

     

    • fileSystemDirectoryEntry.createReader()

    >FileSystemDirectoryReader 객체 반환

    엣지는 WebKitDirectoryReader

     

     

    • fileSystemDirectoryReader.readEntries(successcallback, [errorcallback])

    callback함수는 entries를 인자로 갖고 entries에 디렉토리 내용물(파일/디렉토리)들이 담긴다.

    디렉토리면 > FileSystemDirectoryEntry 객체

    파일이면 > FileSystemFileEntry 객체

     

    readEntries메소드는 비동기로 처리되기 때문에

    디렉토리에 하위 디렉토리가 있는경우 promise나 async/await 문법으로 순서를 맞춰주는 것이 좋다.

     

     

     

     

    파일을 다운로드할때 ajax작성해서 서버에 비동기요청을

    보내고 응답을 받고 하는 과정이 번거로우면

    a태그의 download 속성 이용

    <a download="파일이름">클릭해서 다운로드</a>

     

    let blog = new Blob(데이터,{type: 'type/format'})

    let url = URL.createObject(blob) //이진데이터를 url형태로 인코딩

     

    a.href = url 

    지정시 해당 파일이름으로 url요청=>이진데이터 다운로드

     

    Blob(array, options)

    array는 ArrayBuffer, ArrayBufferView, Blob, DOMString 객체가 온다

    options는 객체 {key : value} 형태로 전달한다.

     

    URL(blob)

    blob는 Blob, File 객체가 온다.

     

     


     

    필요한모듈과 용도

    formidable : FormData 파싱

    fs : 파일시스템 제어

    path : 디렉토리 생성시 경로설정 편하게

     

     

    const form = formidable.IncomingForm();
    
    form.parse(req, (err, fields, files)=>{
    //    Ojbect.keys(files)로 키배열 얻고 배열함수로 순환하며 객체를 차례대로 접근해 처리
    });
    
    

     

    한글있는 파일이 안깨지려면 html파일 <head>에 <meta charset="utf-8" /> 넣어야한다.

     

    form.encoding = "utf-8";        //저장시 인코딩깨진다면 설정변경

    form.keepExtensions = true;    //uploadDir 경로에 파일쓸 때 원래 확장자로 사용하려면

     

     

     

    경로변경

    fs.renameSync(oldpath, newpath)

    임시저장소에서 쉽게 원하는 경로로 변경가능하다.

     

    ※디스크 파티션이 다른경우 에러※

    Error: EXDEV, cross-device link not permitted
    임시저장디렉토리와 지정한 디렉토리의 디스크 파티션이 다른경우

     

    처리하기전 uploadDir 를 설정해 같은 파티션내로 변경

    const form = formidable.IncomingForm();
    form.uploadDir = __dirname + "/tmp" 

     

     

     

    form.on(event, callback) : 이벤트처리

    form.parse()로 파싱하면서 발생하는 이벤트처리

     

    form.on("progress", callback(byteReceived, byteExpected){  })   //중간처리과정알림. progress bar 만들때 보통 사용

    form.on("error", callback(err){ })              //에러발생시

    form.on("end", callback( ){ })              //파일처리가 모두 끝난 뒤 발생

     

     

     

    Formidable의 File 객체

     

    file.size

    file.path

    file.name

    file.type

Designed by Tistory.