Storage API

앱 개발의 거의 모든 측면에는 데이터를 전송하거나 수신하는 요소가 포함됩니다. 기본사항부터 MVC 프레임워크를 사용하여 데이터가 데이터에 관한 앱의 뷰와 완전히 분리되도록 앱을 설계하고 구현해야 합니다 (MVC 아키텍처 참고).

또한 앱이 오프라인일 때 데이터가 처리되는 방식도 고려해야 합니다 (오프라인 우선 참고). 이 문서에서는 로컬에서 데이터를 전송, 수신, 저장하기 위한 저장소 옵션을 간략하게 소개합니다. 나머지 부분에서는 Chrome의 File System API 및 Sync File System API를 사용하는 방법을 보여줍니다 (fileSystem APIsyncFileSystem API 참고).

스토리지 옵션

패키지 앱은 데이터를 주고받기 위해 다양한 메커니즘을 사용합니다. 외부 데이터 (리소스, 웹페이지)의 경우 콘텐츠 보안 정책 (CSP)을 알고 있어야 합니다. Chrome 확장 프로그램과 마찬가지로 교차 출처 XMLHttpRequests를 사용하여 원격 서버와 통신할 수 있습니다. 외부 페이지를 격리하여 앱의 나머지 부분을 보호할 수도 있습니다 (외부 웹 페이지 삽입 참고).

데이터를 로컬에 저장할 때 Chrome Storage API를 사용하여 소량의 문자열 데이터를 저장하고 IndexedDB를 사용하여 구조화된 데이터를 저장할 수 있습니다. IndexedDB를 사용하면 자바스크립트 객체를 객체 저장소에 유지하고 저장소의 색인을 사용하여 데이터를 쿼리할 수 있습니다. 자세한 내용은 HTML5 Rock의 간단한 할 일 목록 가이드를 참조하세요. 바이너리 데이터와 같은 다른 모든 유형의 데이터의 경우 파일 시스템 및 동기화 파일 시스템 API를 사용합니다.

Chrome의 파일 시스템 및 동기화 파일 시스템 API는 HTML5 FileSystem API를 확장합니다. Chrome의 Filesystem API를 사용하면 앱이 사용자 로컬 파일 시스템의 샌드박스 처리된 섹션을 만들고 읽고 탐색하고 이 섹션에 쓸 수 있습니다. 예를 들어 사진 공유 앱은 Filesystem API를 사용하여 사용자가 선택한 사진을 읽고 쓸 수 있습니다.

Chrome의 Sync Filesystem API를 사용하면 앱이 사용자의 Google 드라이브에 데이터를 저장하고 동기화하여 서로 다른 클라이언트에서 동일한 데이터를 사용할 수 있습니다. 예를 들어 클라우드 지원 텍스트 편집기 앱은 새 텍스트 파일을 사용자의 Google Drive 계정에 자동으로 동기화할 수 있습니다. 사용자가 새 클라이언트에서 텍스트 편집기를 열면 Google Drive는 새 텍스트 파일을 텍스트 편집기의 인스턴스로 푸시합니다.

Chrome Filesystem API 사용

파일 시스템 권한 추가 중

Chrome의 File System API를 사용하려면 영구 데이터를 저장할 수 있는 권한을 사용자로부터 얻도록 매니페스트에 'fileSystem' 권한을 추가해야 합니다.

"permissions": [
  "...",
  "fileSystem"
]

파일 선택을 위한 사용자 옵션

사용자는 항상 그렇듯이 파일을 선택하기를 기대합니다. 최소한 '파일 선택' 버튼과 표준 파일 선택기가 필요합니다. 앱에서 파일 처리 방식을 많이 사용하는 경우 드래그 앤 드롭도 구현해야 합니다 (아래 참조 및 네이티브 HTML5 드래그 앤 드롭 참조).

fileEntry의 경로 가져오기

사용자가 선택한 파일의 전체 경로 fileEntry를 가져오려면 getDisplayPath()를 호출합니다.

function displayPath(fileEntry) {
  chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
    console.log(path)
  });
}

드래그 앤 드롭 구현

드래그 앤 드롭 선택을 구현해야 하는 경우 filesystem-access 샘플의 드래그 앤 드롭 파일 컨트롤러 (dnd.js)로 시작하는 것이 좋습니다. 컨트롤러는 드래그 앤 드롭을 통해 DataTransferItem에서 파일 항목을 만듭니다. 이 예에서는 fileEntry이 첫 번째 드롭된 항목으로 설정됩니다.

var dnd = new DnDFileController('body', function(data) {
  var fileEntry = data.items[0].webkitGetAsEntry();
  displayPath(fileEntry);
});

파일 읽기

다음 코드는 파일을 열고 (읽기 전용) FileReader 객체를 사용하여 텍스트로 읽습니다. 파일이 없으면 오류가 발생합니다.

var chosenFileEntry = null;

chooseFileButton.addEventListener('click', function(e) {
  chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {

    readOnlyEntry.file(function(file) {
      var reader = new FileReader();

      reader.onerror = errorHandler;
      reader.onloadend = function(e) {
        console.log(e.target.result);
      };

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

파일 쓰기

파일 작성의 일반적인 두 가지 사용 사례는 '저장'과 '다른 이름으로 저장'입니다. 다음 코드는 읽기 전용 chosenFileEntry에서 writableEntry를 만들고 선택된 파일을 여기에 씁니다.

 chrome.fileSystem.getWritableEntry(chosenFileEntry, function(writableFileEntry) {
    writableFileEntry.createWriter(function(writer) {
      writer.onerror = errorHandler;
      writer.onwriteend = callback;

    chosenFileEntry.file(function(file) {
      writer.write(file);
    });
  }, errorHandler);
});

다음 코드는 '다른 이름으로 저장' 기능으로 새 파일을 만들고 writer.write() 메서드를 사용하여 파일에 새 blob을 씁니다.

chrome.fileSystem.chooseEntry({type: 'saveFile'}, function(writableFileEntry) {
    writableFileEntry.createWriter(function(writer) {
      writer.onerror = errorHandler;
      writer.onwriteend = function(e) {
        console.log('write complete');
      };
      writer.write(new Blob(['1234567890'], {type: 'text/plain'}));
    }, errorHandler);
});

Chrome 동기화 파일 시스템 API 사용

동기화 가능한 파일 저장소를 사용하면 반환된 데이터 객체를 FileSystem API의 로컬 오프라인 파일 시스템과 동일한 방식으로 작업할 수 있지만, 해당 데이터를 Google Drive에 자동으로 동기화하고 추가합니다.

동기화 파일 시스템 권한 추가

Chrome의 Sync Filesystem API를 사용하려면 매니페스트에 'syncFileSystem' 권한을 추가해야 영구 데이터를 저장하고 동기화할 수 있는 권한을 사용자에게서 얻을 수 있습니다.

"permissions": [
  "...",
  "syncFileSystem"
]

동기화 가능한 파일 저장소 시작

앱에서 동기화 가능한 파일 저장소를 시작하려면 syncFileSystem.requestFileSystem을 호출하면 됩니다. 이 메서드는 Google Drive에서 지원하는 동기화 가능한 파일 시스템을 반환합니다. 예를 들면 다음과 같습니다.

chrome.syncFileSystem.requestFileSystem(function (fs) {
   // FileSystem API should just work on the returned 'fs'.
   fs.root.getFile('test.txt', {create:true}, getEntryCallback, errorCallback);
});

파일 동기화 상태 정보

syncFileSystem.getFileStatus를 사용하여 현재 파일의 동기화 상태를 가져옵니다.

chrome.syncFileSystem.getFileStatus(entry, function(status) {...});

파일 동기화 상태 값은 'synced', 'pending', 'conflicting' 중 하나일 수 있습니다. '동기화됨'은 파일이 완전히 동기화되었음을 의미합니다. Google Drive에 동기화되지 않은 대기 중인 로컬 변경사항이 없습니다. 하지만 Google Drive 측에 아직 가져오지 않은 변경사항이 있을 수 있습니다.

'대기 중'은 파일에 아직 Google 드라이브에 동기화되지 않은 대기 중인 변경사항이 있음을 의미합니다. 앱이 온라인에서 실행 중이면 로컬 변경사항이 거의 즉시 Google Drive에 동기화되고 syncFileSystem.onFileStatusChanged 이벤트가 'synced' 상태와 함께 실행됩니다(자세한 내용은 아래 참조).

파일의 상태가 'conflicting'로 변경되면 syncFileSystem.onFileStatusChanged가 실행됩니다. '충돌'은 로컬 저장소와 Google Drive 모두에 변경사항이 충돌한다는 의미입니다. 충돌 해결 정책이 'manual'로 설정된 경우에만 파일이 이 상태일 수 있습니다. 기본 정책은 'last_write_win'이며 충돌은 간단한 마지막 쓰기 정책으로 자동으로 해결됩니다. 시스템의 충돌 해결 정책은 syncFileSystem.setConflictResolutionPolicy를 통해 변경할 수 있습니다.

충돌 해결 정책이 'manual'로 설정되고 파일이 'conflicting' 상태가 되면 앱은 파일을 로컬 오프라인 파일로 계속 읽고 쓸 수 있지만 변경사항은 동기화되지 않으며 충돌이 해결될 때까지 다른 클라이언트의 원격 변경사항에서 분리된 상태로 유지됩니다. 충돌을 해결하는 가장 쉬운 방법은 파일의 로컬 버전을 삭제하거나 이름을 변경하는 것입니다. 이렇게 하면 원격 버전이 강제로 동기화되고 충돌 상태가 해결되며 'synced' 상태로 onFileStatusChanged 이벤트가 실행됩니다.

동기화된 상태의 변경사항 리슨

syncFileSystem.onFileStatusChanged 이벤트는 파일의 동기화 상태가 변경되면 실행됩니다. 예를 들어 파일이 대기 중인 변경사항이 있고 '대기 중' 상태에 있다고 가정해 보겠습니다. 앱이 오프라인 상태여서 변경사항이 곧 동기화될 수 있습니다. 동기화 서비스가 대기 중인 로컬 변경사항을 감지하고 변경사항을 Google Drive에 업로드하면 동기화 서비스는 { fileEntry:a fileEntry for the file, status: 'synced', action: 'updated', direction: 'local_to_remote' } 값을 사용하여 onFileStatusChanged 이벤트를 실행합니다.

마찬가지로, 동기화 서비스는 로컬 활동과 관계없이 다른 클라이언트의 원격 변경사항을 감지하고 변경사항을 Google Drive에서 로컬 저장소로 다운로드할 수 있습니다. 원격 변경이 새 파일을 추가하기 위한 것이었다면 { fileEntry: a fileEntry for the file, status: 'synced', action: 'added', direction: 'remote_to_local' } 값이 포함된 이벤트가 실행됩니다.

로컬 측과 원격 측에 동일한 파일의 변경사항이 충돌하고 충돌 해결 정책이 'manual'로 설정된 경우 파일 상태가 conflicting 상태로 변경되고 동기화 서비스에서 분리되며 충돌이 해결될 때까지 동기화되지 않습니다. 이 경우 { fileEntry: a fileEntry for the file, status: 'conflicting', action: null, direction: null } 값을 가진 이벤트가 실행됩니다.

모든 상태 변경에 응답하는 이 이벤트에 대한 리스너를 추가할 수 있습니다. 예를 들어 Chrome 뮤직 플레이어 앱은 Google 드라이브에서 동기화된 새 음악을 리슨하지만 아직 특정 클라이언트에서 사용자의 로컬 저장소로 가져오지는 않습니다. 발견된 모든 음악은 해당 클라이언트에 동기화됩니다.

chrome.syncFileSystem.onFileStatusChanged.addListener(function(fileInfo) {
  if (fileInfo.status === 'synced') {
    if (fileInfo.direction === 'remote_to_local') {
      if (fileInfo.action === 'added') {
        db.add(fileInfo.fileEntry);
      } else if (fileInfo.action === 'deleted') {
        db.remove(fileInfo.fileEntry);
      }
    }
  }
});

API 사용량 확인 중

API에서 사용 중인 데이터의 양을 확인하려면 앱의 로컬 샌드박스 디렉터리 또는 syncFileSystem.getUsageAndQuota가 반환한 사용량 바이트를 쿼리합니다.

chrome.syncFileSystem.getUsageAndQuota(fileSystem, function (storageInfo) {
   updateUsageInfo(storageInfo.usageBytes);
   updateQuotaInfo(storageInfo.quotaBytes);
});

사용자의 Google Drive 동기화 백엔드 서비스 스토리지를 확인할 수도 있습니다. 동기화된 파일은 숨겨진 Google Drive 폴더인 Chrome 동기화 가능 파일 시스템에 저장됩니다. 폴더가 '내 드라이브' 목록에 표시되지 않지만 검색창에서 폴더 이름을 검색하여 액세스할 수 있습니다. 원격 폴더 레이아웃은 버전 간에 이전 버전과의 호환성을 유지하지 않을 수 있습니다.