Interfejsy API pamięci masowej

Niemal każdy aspekt tworzenia aplikacji obejmuje jakiś element wysyłania lub odbierania danych. Zacznij od podstaw. Użyj platformy MVC, która ułatwi Ci zaprojektowanie i wdrożenie aplikacji w taki sposób, aby dane były całkowicie oddzielone od widoku tych danych przez aplikację (patrz Architektura MVC).

Musisz też wziąć pod uwagę sposób postępowania z danymi, gdy aplikacja działa w trybie offline (patrz Najpierw offline). W tym dokumencie pokrótce przedstawiamy opcje przechowywania danych służące do wysyłania, odbierania i zapisywania danych lokalnie. W dalszej części dokumentu omawiamy sposoby używania interfejsów API systemu plików Chrome i synchronizacji plików (zobacz też interfejsy fileSystem API i syncFileSystem API).

Opcje miejsca na dysku

Aplikacje w pakietach korzystają z wielu różnych mechanizmów wysyłania i odbierania danych. W przypadku danych zewnętrznych (zasobów, stron internetowych) musisz znać się na Content Security Policy (CSP). Podobnie jak w przypadku rozszerzeń do Chrome, do komunikacji z serwerami zdalnymi możesz używać transmisji XMLHttpRequests z innych domen. Możesz też wyizolować strony zewnętrzne, by reszta aplikacji była bezpieczna (patrz Umieszczanie zewnętrznych stron internetowych).

Jeśli dane zapisujesz lokalnie, możesz użyć interfejsu Chrome Storage API, aby zapisać niewielkie ilości danych w postaci ciągów znaków, i narzędzia IndexedDB, by zapisywać uporządkowane dane. Dzięki IndexedDB możesz przechowywać obiekty JavaScript w magazynie obiektów i używać indeksów sklepu do wysyłania zapytań o dane (więcej informacji znajdziesz w samouczeku prostych zadań na liście zadań na stronie HTML5 Rock). W przypadku pozostałych typów danych, takich jak dane binarne, używaj interfejsów API systemu plików i synchronizacji plików.

Interfejsy API systemu plików i synchronizacji plików w Chrome rozszerzają interfejs HTML5 FileSystem API. Dzięki interfejsowi Filesystem API w Chrome aplikacje mogą tworzyć, odczytywać, otwierać i zapisywać sekcję w piaskownicy lokalnego systemu plików użytkownika. Na przykład aplikacja do udostępniania zdjęć może używać interfejsu Filesystem API do odczytywania i zapisywania dowolnych zdjęć wybranych przez użytkownika.

Dzięki interfejsowi Sync Filesystem API w Chrome aplikacje mogą zapisywać i synchronizować dane na Dysku Google użytkownika, dzięki czemu te same dane mogą być dostępne w różnych klientach. Na przykład obsługiwany w chmurze edytor tekstu może automatycznie synchronizować nowe pliki tekstowe z kontem użytkownika Dysku Google. Gdy użytkownik otworzy edytor tekstu w nowym kliencie, Dysk Google przekaże nowe pliki tekstowe do tego wystąpienia edytora tekstu.

Korzystanie z interfejsu Chrome Filesystem API

Dodawanie uprawnień do systemu plików

Aby korzystać z interfejsu File System API Chrome, musisz dodać do pliku manifestu uprawnienie „fileSystem”. Pozwoli Ci to uzyskać od użytkownika uprawnienia do przechowywania trwałych danych.

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

Opcje użytkownika dotyczące wyboru plików

Użytkownicy oczekują, że będą wybierać pliki tak samo jak do tej pory. Wymagają przynajmniej przycisku „Wybierz plik” i standardowego narzędzia do wybierania plików. Jeśli Twoja aplikacja intensywnie korzysta z obsługi plików, warto wdrożyć funkcję „przeciągnij i upuść” (zobacz poniżej oraz zapoznaj się z natywnymi przeciąganiem i upuszczaniem plików HTML5).

Uzyskiwanie ścieżki elementu fileEntry

Aby uzyskać pełną ścieżkę pliku wybranego przez użytkownika (fileEntry), wywołaj funkcję getDisplayPath():

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

Implementacja metodą „przeciągnij i upuść”

Jeśli chcesz zastosować wybór metodą „przeciągnij i upuść”, dobrym punktem wyjścia będzie kontroler plików (dnd.js) w przykładzie dostęp do systemu plików. Kontroler tworzy wpis pliku z tabeli DataTransferItem metodą „przeciągnij i upuść”. W tym przykładzie fileEntry jest ustawiony na pierwszy usunięty element.

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

Odczytywanie pliku

Ten kod otwiera plik (tylko do odczytu) i odczytuje go jako tekst za pomocą obiektu FileReader. Jeśli plik nie istnieje, zgłaszany jest błąd.

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);
    });
    });
});

Zapisywanie pliku

Dwa najczęstsze przypadki użycia zapisu pliku to „Zapisz” i „Zapisz jako”. Ten kod tworzy writableEntry z pliku chosenFileEntry tylko do odczytu i zapisuje w nim wybrany plik.

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

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

Poniższy kod tworzy nowy plik z funkcją „Zapisz jako” i zapisuje w nim nowy obiekt blob za pomocą metody writer.write().

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);
});

Korzystanie z interfejsu Chrome Sync Filesystem API

Dzięki możliwości synchronizowania plików danych zwróconych obiektów danych można obsługiwać w taki sam sposób jak lokalne systemy plików offline za pomocą interfejsu FileSystem API, ale z dodatkową (i automatyczną) synchronizacją tych danych z Dyskiem Google.

Dodawanie uprawnienia do systemu plików synchronizacji

Aby używać interfejsu Sync Filesystem API w Chrome, musisz dodać do pliku manifestu uprawnienie „syncFileSystem”. Dzięki temu możesz uzyskać od użytkownika uprawnienia do przechowywania i synchronizowania danych trwałych.

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

Rozpoczynam przechowywanie plików z możliwością synchronizacji

Aby rozpocząć przechowywanie plików w aplikacji z możliwością synchronizacji, po prostu wywołaj syncFileSystem.requestFileSystem. Ta metoda zwraca zsynchronizowany system plików oparty na Dysku Google, na przykład:

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

Informacje o stanie synchronizacji plików

Za pomocą polecenia syncFileSystem.getFileStatus możesz sprawdzić stan synchronizacji bieżącego pliku:

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

Możliwe wartości stanu synchronizacji pliku: 'synced', 'pending' lub 'conflicting'. „Zsynchronizowano” oznacza, że plik jest w pełni zsynchronizowany i nie ma żadnych oczekujących zmian lokalnych, które nie zostały zsynchronizowane z Dyskiem Google. Na Dysku Google mogą jednak być zmiany oczekujące, które nie zostały jeszcze pobrane.

„Oczekujący” oznacza, że zmiany dotyczące pliku nie zostały jeszcze zsynchronizowane z Dyskiem Google. Jeśli aplikacja działa online, zmiany lokalne są niemal natychmiast synchronizowane z Dyskiem Google, a zdarzenie syncFileSystem.onFileStatusChanged jest wywoływane ze stanem 'synced' (więcej informacji znajdziesz poniżej).

Parametr syncFileSystem.onFileStatusChanged jest uruchamiany, gdy stan pliku zmieni się na 'conflicting'. „Konflikt” oznacza, że zmiany występują zarówno w pamięci lokalnej, jak i na Dysku Google. Plik może mieć ten stan tylko wtedy, gdy zasada rozwiązywania konfliktów jest ustawiona na 'manual'. Domyślna zasada to 'last_write_win', a konflikty są automatycznie rozwiązywane za pomocą prostej zasady ostatniego zapisu i wygrywania. Zasady rozwiązywania konfliktów w systemie można zmienić za pomocą zasady syncFileSystem.setConflictResolutionPolicy.

Jeśli zasada rozwiązywania konfliktów jest ustawiona na 'manual', a plik ma stan 'conflicting', aplikacja nadal może odczytywać i zapisywać plik jako lokalny plik offline, ale zmiany nie są synchronizowane, a plik jest odłączony od zdalnych zmian wprowadzonych w innych klientach do czasu rozwiązania konfliktu. Najłatwiejszym sposobem rozwiązania konfliktu jest usunięcie lokalnej wersji pliku lub zmianę jej nazwy. Wymusza to synchronizację wersji zdalnej, eliminuje konflikt, a zdarzenie onFileStatusChanged jest wywoływane ze stanem 'synced'.

Nasłuchiwanie zmian stanu synchronizacji

Zdarzenie syncFileSystem.onFileStatusChanged jest wywoływane w przypadku zmiany stanu synchronizacji pliku. Załóżmy na przykład, że plik zawiera zmiany oczekujące i ma stan „oczekujący”. Aplikacja mogła działać w trybie offline, więc wkrótce nastąpi synchronizacja zmian. Gdy usługa synchronizacji wykryje oczekującą zmianę lokalną i prześle ją na Dysk Google, wywoła zdarzenie onFileStatusChanged z następującymi wartościami: { fileEntry:a fileEntry for the file, status: 'synced', action: 'updated', direction: 'local_to_remote' }.

Podobnie, niezależnie od działań lokalnych, usługa synchronizacji może wykrywać zdalne zmiany wprowadzone przez innego klienta i pobierać je z Dysku Google do pamięci lokalnej. Jeśli zmiana zdalna polegała na dodaniu nowego pliku, wywoływane jest zdarzenie o tych wartościach: { fileEntry: a fileEntry for the file, status: 'synced', action: 'added', direction: 'remote_to_local' }.

Jeśli zarówno strona lokalna, jak i zdalna mają w tym samym pliku powodujące konflikt zmiany, a zasada rozwiązywania konfliktów jest ustawiona na 'manual', stan pliku zostaje zmieniony na stan conflicting, plik zostanie odłączony od usługi synchronizacji i nie będzie synchronizowany, dopóki konflikt nie zostanie rozwiązany. W takim przypadku wywoływane jest zdarzenie o tych wartościach: { fileEntry: a fileEntry for the file, status: 'conflicting', action: null, direction: null }.

Możesz dodać do tego zdarzenia detektor, który będzie reagował na wszelkie zmiany stanu. Na przykład aplikacja Chrome Music Player nasłuchuje nowej muzyki zsynchronizowanej z Dysku Google, ale nie została jeszcze zaimportowana do pamięci lokalnej użytkownika w danym kliencie. Znaleziona muzyka jest synchronizowana z klientem:

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);
      }
    }
  }
});

Sprawdzam wykorzystanie interfejsu API

Aby sprawdzić ilość danych używanych przez interfejs API, wyślij zapytanie do lokalnego katalogu aplikacji w trybie piaskownicy lub do bajtów wykorzystania zwróconych przez metodę syncFileSystem.getUsageAndQuota:

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

Możesz też sprawdzić pamięć backendu usługi synchronizacji użytkownika (na Dysku Google). Zsynchronizowane pliki są zapisywane w ukrytym folderze Dysku Google Chrome Syncable FileSystem. Folder nie będzie widoczny na liście „Mój dysk”, ale będzie można go otworzyć, wyszukując nazwę folderu w polu wyszukiwania. (Pamiętaj, że nie ma gwarancji, że układ folderów zdalnych będzie zgodny wstecznie między kolejnymi wersjami.