2014-12-22 11 views
16

Consente di supporre un caso in cui una stringa enorme viene generata da una piccola stringa utilizzando una logica javascript e quindi il file di testo viene forzato a essere scaricato nel browser.È possibile eseguire lo streaming di un flusso di ottetto generato in javascript?

Questo è possibile utilizzando un ottetto-stream scaricare mettendolo come un href, come accennato in questa risposta:

Create a file in memory for user to download, not through server.

function download(filename, text) { 
    var pom = document.createElement('a'); 
    pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); 
    pom.setAttribute('download', filename); 
    pom.click(); 
} 

Ma questa soluzione richiede 'testo' ad essere pienamente generato prima di essere spinto per il download, quindi dovrà essere tenuto in memoria del browser completamente.

È possibile eseguire lo streaming del testo non appena viene generato utilizzando CLIENT SIDE LOGIC SOLO?

Ad esempio:

var inputString = "A"; 
var outStr = ""; 
for(var i = 0; i < 10000000 ; i++) 
{ 
    /* concatenate inputString to output on the go */ 
} 
+0

Se non si trova una soluzione a questo problema, potrebbe essere un'alternativa per mettere i dati in un [Blob] (https://developer.mozilla.org/ en-US/docs/Web/API/Blob) e quindi utilizzare [createObjectURL()] (https://developer.mozilla.org/de/docs/Web/API/URL.createObjectURL) per generare un collegamento per il download . I browser probabilmente memorizzeranno nella cache i dati sul disco e, soprattutto, non disporrai di un URL di dati di grandi dimensioni. – Phillip

+0

@Phillip Non voglio archiviare tutto il contenuto in un file blob o zip, o usare indexDb, lo streaming è il requisito. – DhruvPathak

+1

no. tutte le attuali tecnologie del browser richiedono la conoscenza della dimensione complessiva prima di inviare i primi byte; solo elementi più recenti lato server come node.js possono utilizzare il chunking http1.1. dovrai usare molte connessioni o buffer. potresti essere in grado di utilizzare websockets, ma ciò richiederà un po 'di personalizzazione su entrambe le estremità. – dandavis

risposta

8

Sì & n. No perché non c'è un modo per scrivere su file con solo javascript lato client. Tipo. Puoi chiedere a un utente di scaricare & di salvare un file, ma come hai detto, il codice deve generare l'intero file prima che il download avvenga. Nota: con "stream" presumo che tu intenda stream to file (scrive costantemente su un file) & da "SOLO LOGIC SOLO CLIENT". Suppongo che intendi nel browser.

Sembra che Mozilla stia lavorando su un modo per consentire al codice lato client di interagire con i file. Ecco il sì. Tipo. Hanno il loro file system api che consente di interagire con (scrivere sul) file system delle macchine locali. In particolare, c'è una funzione che ti consente di effettuare il write an input stream to a file. Tuttavia, ci sono alcuni asterischi:

1) sembra che l'intero sistema sia deprecato; incoraggiano gli sviluppatori a utilizzare OS.file oltre il file I/O

2) Devi usare XPConnect, un sistema che consente di accedere biblioteca XPCOM (componente di Mozilla) in javascript. Se vuoi farlo nel browser, sembra che solo le estensioni di firefox abbiano le autorizzazioni appropriate per interagire con quei componenti(). Se non volevi farlo nel browser, potresti ovviamente usare il nodo.

Sicuramente, più complicazioni sono destinate a comparire durante l'implementazione. Ma questo sembra il percorso più sicuro in avanti, visto che OS.File permette di accedere a funzioni come OS.File.writeAtomic() & base write to file

Detto questo, non è quel grande di un percorso, ma spero che questo ti dà un solido punto di partenza. Come menzionato @dandavis, i browser (ad esempio "logica lato client") sono progettati per non consentire questo genere di cose. Sarebbe un enorme errore di supervisione/sicurezza se un sito web potrebbe interagire con il file system locale di qualsiasi utente.

risorse aggiuntive:
Wikipedia on XPConnect
Guide on working with XPCOM in javascript - non può essere che utile

4

C'è un modo per fare questo, ma si basa su un'API Chrome unico filesystem. Creeremo e scriveremo in un file temporaneo in un file system sandboxed e lo coperemo nel file system normale una volta che abbiamo finito. In questo modo non è necessario memorizzare l'intero file in memoria.La versione asincrona dell'API di Chrome non viene attualmente considerata per la standardizzazione da W3C, ma la versione sincrona (che utilizza i web worker) lo è. Se il supporto del browser è un problema, allora questa risposta non fa per te.

L'API funziona in questo modo: Innanzitutto, viene visualizzata la funzione requestFileSystem() dal browser. Attualmente è preceduto da "WebKit":

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

Avanti, chiediamo un file system temporaneo (in questo modo non abbiamo bisogno di chiedere il permesso dell'utente):

var fileSystem; //This will store the fileSystem for later access 
var fileSize = 1024*1024 //Our maximum file system size. 
function errorHandler(e) { 
    console.log('Error: ' + e.name); 
} 
window.requestFileSystem(window.TEMPORARY, fileSize, function (fs) { fileSystem = fs; }, errorHandler); 

Ora che abbiamo accesso al file system è il momento di creare un file:

var fileOptions = { 
    create: true, //If the file is not found, create it 
    exclusive: false //Don't throw an error if the file doesn't exist 
}; 

Qui si chiama la funzione getFile(), che può creare un file se non esiste. All'interno del callback, possiamo creare un nuovo fileWriter per scrivere sul file. Lo fileWriter viene quindi spostato alla fine del file e creiamo un nuovo BLOB di testo da aggiungere ad esso.

fileSystem.root.getFile(fileName, fileOptions, function(fileEntry) { 
    fileEntry.createWriter(function(fileWriter) { 
     fileWriter.seek(fileWriter.length); 
     var blob = new Blob([STRING_TO_WRITE], {type: 'text/plain'}); 
     fileWriter.write(blob); 
    }, errorHandler); 
}); 

Si noti che questa API non viene salvata nel normale file system dell'utente. Invece, salva in una speciale cartella sandbox. Se si desidera salvarlo nel file system dell'utente, è possibile creare un collegamento filesystem:. Quando l'utente fa clic su di esso, chiederà loro di salvarlo. Dopo averlo salvato, puoi rimuovere il file temporaneo.

Questa funzione genera il link filesystem utilizzando la funzione 's il fileEntrytoURL():

var save = function() { 
    var download = document.querySelector("a[download]"); 
    if (!fileSystem) { return; } 
    fileSystem.root.getFile(fileName, {create: false, exclusive: true}, function(fileEntry) { 
    download.href = fileEntry.toURL(); 
    }, errorHandler); 
} 

Utilizzando un collegamento con l'attributo scaricare costringerà il download del file.

<a download></a> 

Ecco un plunker che illustra questo: http://plnkr.co/edit/q6ihXWEXSOtutbEy1b5G?p=preview

Speriamo che questo compie ciò che si desidera. È possibile aggiungere continuamente al file, non verrà mantenuto in memoria, ma sarà nel file system sandbox fino a quando l'utente non lo salverà sul normale file system.

Per ulteriori informazioni, dare un'occhiata a questo HTML5rocks article o this one se si desidera utilizzare l'API di Worker sincrono più recente.

2

Lo suggerirei come @quantumwannabe describes, utilizzando il file sandbox temporaneo per aggiungere blocchi.

Ma c'è un modo nuovo che può essere utilizzato oggi (dietro una bandiera), ma verrà attivata nella prossima versione di Chrome (52)

E qui è dove mi farò @ KeenanLidral-Porter risposta errata .E @quantumwannabe rispondere a un passo inutile
Perché ora c'è un modo per scrivere un flusso al file system direttamente: StreamSaver.js

Esso agisce come se ci fosse un server di invio intestazione octet-stream e dice al browser per scaricare pezzi di i dati con l'aiuto di un operaio di servizio

const writeStream = streamSaver.createWriteStream('filename.txt') 
const encoder = new TextEncoder 
let data = 'a'.repeat(1024) // Writing some stuff triggers the save dialog to show 
let uint8array = encoder.encode(data + "\n\n") 

writeStream.write(uint8array) // Write some data when you got some 
writeStream.close() // End the saving 
+1

Si prega di postare una spiegazione di come funziona quella libreria, e forse il codice specifico per le API che usa, invece di solo un link github. – Bergi

+0

@Endless 'ReadableStream' è disponibile su chromium, chrome 50 – guest271314

Problemi correlati