2016-08-31 18 views
7

Mam obiekt XHR, który pobiera plik 1 GB.Duży plik blob w JavaScript

function getFile(callback) 
{ 
    var xhr = new XMLHttpRequest(); 
    xhr.onload = function() { 
     if (xhr.status == 200) { 
      callback.apply(xhr); 
     }else{ 
      console.log("Request error: " + xhr.statusText); 
     } 
    }; 

    xhr.open('GET', 'download', true); 
    xhr.onprogress = updateProgress; 
    xhr.responseType = "arraybuffer"; 
    xhr.send(); 
} 

Ale File API nie można załadować do pamięci wszystkich, że nawet od pracownika wyrzuca z pamięci ...

btn.addEventListener('click', function() { 
    getFile(function() { 
     var worker = new Worker("js/saving.worker.js"); 
     worker.onmessage = function(e) { 
      saveAs(e.data); // FileSaver.js it creates URL from blob... but its too large 
     }; 

     worker.postMessage(this.response); 
    }); 
}); 

Web Worker

onmessage = function (e) { 
    var view = new DataView(e.data, 0); 
    var file = new File([view], 'file.zip', {type: "application/zip"}); 
    postMessage('file'); 
}; 

I Nie próbuję skompresować pliku, ten plik jest już skompresowany z serwera.

Myślałem przechowywanie go najpierw na IndexedDB ale będę musiał ładować blob lub złożyć w każdym razie, nawet jeśli robię żądanie przez bajtów zasięgu, prędzej czy później będę musiał zbudować tę gigantyczną plamę ..

Chcę utworzyć blob: url i wysłać go do użytkownika po pobraniu przez przeglądarkę

Będę używać API FileSystem dla Google Chrome, ale chcę zrobić coś dla Firefoxa, zajrzałem do File Aple Api, ale nic ...

Czy muszę utworzyć rozszerzenie firefox, aby zrobić to samo, co FileSystem dla Google Chrome?


Ubuntu 32 bity

+0

Podziałało po pobraniu mniejszy \ * pliku zip.? Błąd wygląda mi znajomo, "brak pamięci". – Hydro

+0

Tak, zadziałało, tylko dla dużych rozmiarów –

+0

Hmm ... czy możesz spróbować ostrzec cokolwiek, gdy zostanie wywołane zdarzenie btn click? Gdy błąd zostanie zgłoszony, podaj nam liczbę alertów, które tu masz. – Hydro

Odpowiedz

6

Ładowanie 1gb + z AJAX nie jest wygodne tylko dla monitorowania postępu pobierania i zapełniać pamięć.

Zamiast tego po prostu wyślę plik z nagłówkiem Content-Disposition, aby zapisać plik.


Istnieją jednak sposoby obejścia go, aby monitorować postęp. Opcja pierwsza to posiadanie drugiego urządzenia sieciowego, które sygnalizuje ile pobrałeś podczas normalnego pobierania z prośbą o pobranie. druga opcja będzie opisana później na dole:


Wiem, że rozmawiałeś o używaniu piaskownego systemu plików Blinks w rozmowie. ale ma pewne wady. Może wymagać pozwolenia, jeśli używa trwałego magazynu. Pozwala tylko na 20% dostępnego dysku, który pozostało. A jeśli Chrome musi zwolnić trochę miejsca, to wyrzuci wszystkie inne tymczasowe pamięci, które były ostatnio używane dla najnowszego pliku. Poza tym nie działa w trybie prywatnym.
Nie wspominając, że został on spada poparcie dla niego i nigdy nie może skończyć się w innych przeglądarkach - ale najprawdopodobniej nie usunie go, ponieważ wiele stron nadal zależą od niego


Jedynym sposobem Ten proces duży plik jest ze strumieniami. Właśnie dlatego stworzyłem StreamSaver. Będzie to działało tylko w bankomacie Blink (chrome & opera), ale ostatecznie będzie obsługiwane przez inne przeglądarki z opcją whatwg, aby utworzyć kopię zapasową jako standard.

fetch(url).then(res => { 
    // One idea is to get the filename from Content-Disposition header... 
    const size = ~~res.headers.get('Content-Length') 
    const fileStream = streamSaver.createWriteStream('filename.zip', size) 
    const writeStream = fileStream.getWriter() 
    // Later you will be able to just simply do 
    // res.body.pipeTo(fileStream) 
    // instead of pumping 

    const reader = res.body.getReader() 
    const pump =() => reader.read() 
     .then(({ value, done }) => { 
      // here you know how large the value (chunk) is and you can 
      // figure out the download speed/progress when comparing it to the size 

      return done 
       ? writeStream.close() 
       : writeStream.write(value).then(pump) 
     ) 

    // Start the reader 
    pump().then(() => 
     console.log('Closed the stream, Done writing') 
    ) 
}) 

To nie zajmie żadnego pamięć

+0

Czy mogę utworzyć rozszerzenie, które robi mniej więcej to samo dla firefox? Jest jakieś dzieło? –

+0

Prawie wszystko jest możliwe z rozszerzeniem firefox, więc tak myślę. Ale nie sądzę, że ludzie to zainstalują: -/możesz pomóc, pomagając w Firefoksie implementując strumienie :-) – Endless

4

Mam teorię, że jest, jeśli podzielić plik na kawałki i przechowywać je w IndexedDB a potem połączyć je razem to będzie działać

kropelka nie jest wykonana z danymi ... to nic więcej jak wskaźniki do gdzie plik można odczytać z enter image description here

Znaczenie jeśli je przechowywać w IndexedDB a następnie zrobić coś takiego (używając FileSaver lub alternatywne)

finalBlob = new Blob([blob_A_fromDB, blob_B_fromDB]) 
saveAs(finalBlob, 'filename.zip') 

ale nie mogę tego potwierdzić, ponieważ nie zostały przetestowane go, byłoby dobrze, gdyby ktoś inny mógłby

+1

Zacząłem testować to. I myślę, że to działa :) pomóż mi przejrzeć ten problem: https://github.com/jimmywarting/StreamSaver.js/pull/18 – Endless

+0

Próbowałem też, ale nie mam czasu:/ Rozwój jest za późno –

+0

Od plik z 450MB poszło dobrze –