Zapis binarnego pliku z poziomu JavaScriptu

0

Mój poprzedni post opisujący ten problem chyba zniknął (bo chyba go napisałem w dziale newbie), no ale problem jest taki, że mam sobie tablicę bajtów, może to być typowana tablica ale nie musi. Chcę tą tablicę w jakikolwiek w miarę wydajny sposób zrzucić na dysk. Aktualnie mam taki kod: http://4programmers.net/Pastebin/1880

Pytanie: co wrzucić do saveResults, żeby dało się zapisać dane na dysk w 100% niezmienione i z sensowną prędkością (np max kilkanaście sekund na 100 megowy plik)? Szukałem po Googlach, ale nie mam cierpliwości do klejenia rozwiązania z krzywych skrawków.

Wystarczy jak rozwiązanie będzie działało w Chrome.

PS: Pewnie zły dział wybrałem, no ale JavaScript jest wymieniony w opisie tylko tego działu.

1
  1. http://eligrey.com/demos/FileSaver.js/ Obecnie tylko Chrome. Pod wersją nightly Firefoksa działa mniej więcej w połowie. Można się spodziewać, że kiedyś będzie zaimplementowane w większości przeglądarek, bo to standard w3c.
  2. https://github.com/dcneiner/Downloadify (używa flasha)
  3. przekierowanie pod data:application/octet-stream,dane_w_base64, ale w tym przypadku się nie nada, bo jest spore ograniczenie wielkości
0

No dobra, zacząłem zabawę z JavaScriptem, w zasadzie reprezentuję poziom Newbie, ale dopiszę się do własnego wątku tutaj. Użyłem FileSavera (https:*github.com/eligrey/FileSaver.js) i BlobBuildera (https:*github.com/eligrey/BlobBuilder.js) oraz napisałem własne skrypty i mi nie działa :P

js/Chunk.js:

Chunk.Type = {
    Untyped : "untyped",
    Typed : "typed"
};

Chunk = function(type) {
    this.type = type;
    this.ChunkSize = 64 * 1024;
    if (this.type === Chunk.Type.Untyped) {
        this.array = new Array();
        for (var i = 0; i < this.ChunkSize; i++) {
            this.array.push(0);
        }
    } else if (this.type === Chunk.Type.Typed) {
        this.array = new Uint8Array(this.ChunkSize);
    } else {
        throw "Invalid type";
    }
    this.position = 0;
    this.put = function(value) {
        this.array[this.position] = value;
        this.position++;
    };
    this.isFull = function() {
        return this.position == this.ChunkSize;
    };
    this.truncated = function() {
        if (this.type === Chunk.Type.Untyped) {
            return this.array.slice(0, this.position);
        } else if (this.type === Chunk.Type.Typed) {
            return this.array.subarray(0, this.position);
        } else {
            throw "Invalid type";
        }
    };
};

js/Streams.js:

ArrayInputStream = function(array) {
    this.position = 0;
    this.array = array;
    this.read = function() {
        if (this.position == this.array.length) {
            return -1;
        } else {
            var result = this.array[this.position];
            this.position++;
            return result;
        }
    }
}

ChunksArrayOutputStream = function(type) {
    this.type = type;
    this.chunkArray = [];
    this.chunk = new Chunk(this.type);
    this.write = function(value) {
        if (this.chunk.isFull()) {
            this.chunkArray.push(this.chunk);
            this.chunk = new Chunk(this.type);
        }
    }
    this.flush = function() {
        this.chunkArray.push(this.chunk);
        this.chunk = null;
    }
}

js/demo.js:

var inputFileChooser = document.getElementById("inputFileChooser");

var loadButton = document.getElementById("loadButton");
var processButton = document.getElementById("processButton");
var saveButton = document.getElementById("saveButton");

loadButton.onclick = loadContents;
processButton.onclick = processData;
saveButton.onclick = saveResults;

function setButtonsState(enabled) {
    loadButton.disabled = !enabled;
    processButton.disabled = !enabled;
    saveButton.disabled = !enabled;
}

var inputStream = null;
var outputStream = null;
function loadContents() {
    var file = inputFileChooser.files[0];
    if (!file)
        return;
    var reader = new FileReader();
    setButtonsState(false);
    reader.readAsArrayBuffer(file);
    reader.onload = loaded;
    reader.onloadend = function (event) {
        setButtonsState(true);
    }
}

function loaded(event) {
    inputStream = new ArrayInputStream(new Uint8Array(event.target.result));
}

function processData() {
    outputStream = new ChunksArrayOutputStream(Chunk.Type.Typed);
    var value;
    while ((value = inputStream.read()) != -1) {
        outputStream.write(value);
    }
}

function saveResults() {
    var bb = new BlobBuilder;
    for (var chunk in outputStream.chunkArray) {
        bb.append(chunk.array);
    }
    var blob = bb.getBlob("example/binary");
    saveAs(blob, "filename.ext");
}

Main.html: http://4programmers.net/Pastebin/1881

W załączniku spakowana wersja gotowa do odpalenia w Chrome.

Wszelkie sugestie co do kodu mile widziane, bo zapewne tutaj jest masa błędów i beznadziejny styl pisania (w końcu do JavaScriptu jestem nieprzyzwyczajony).

1 użytkowników online, w tym zalogowanych: 0, gości: 1