

ブラウザ上で、クライアントPCに保存されている点群データを操作をしようと考えています。

FileAPIで取得したfileオブジェクトを、FileReaderで読み込むことができることはわかりました。

ここからが質問なのですが、FileReaderで読み込んでいるデータを、途中で読み込み処理を停止して、停止した所までのデータを取得・操作することは可能でしょうか？

利用ケースとしては、点群データのヘッダー情報のみが必要で、全部を読み込む必要がなく、少しでも読み込み時間を短くしたいと思っています。全部を読み込んでから操作すればいいのですが、点群データは数10GBを平気で超えることもあり、読み込みに時間がかかるのがボトルネックとなっています。

サンプルコード

[code]

    var fileReader = new FileReader();
    
    fileReader.onprogress = function( event ) {
        if ( event.loaded > 1000000 ) {
            fileReader.abort();
        }
    }
    
    fileReader.onabort = function( event ) {
        // 候補１：ここで途中まで読み込んだArraybufferを取得したい
    
        // 途中まで読み込んだ点群データを操作する処理を記述
    
    }
    
    fileReader.readAsArrayBuffer( fileObj );
    
[/code]


CC BY-SA 4.0
2020-07-30T11:34:57.323
69121
2020-07-30T13:20:15.860
41317
question
javascript html5
javascriptのFileAPIで読み込み途中のデータを取得することは可能ですか？


残念ながら、 `FileReader` ではご希望の動作はできません。しかし、 `File` オブジェクトの [`stream()`
メソッド](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream) によって返される
[`ReadableStream`
インターフェース](https://developer.mozilla.org/ja/docs/Web/API/ReadableStream)
を使えば所望の動作が実現できます。

簡単に処理の流れを説明すると、まず [`getReader()`
メソッド](https://developer.mozilla.org/ja/docs/Web/API/ReadableStream/getReader)
によって
[`ReadableStreamDefaultReader`](https://developer.mozilla.org/ja/docs/Web/API/ReadableStreamDefaultReader)
を取得して、そのオブジェクトの [`read`
メソッド](https://developer.mozilla.org/ja/docs/Web/API/ReadableStreamDefaultReader/read)
に、ストリームから得られた部分データ（チャンク）を扱う関数を渡す形になります。

以下に簡単なテスト用のコードを示します。これは、ファイルを逐次読み込みしてコンソールに出力するだけのものです。

[code]

    <!DOCTYPE html>
    <html>
    <head>
    <title>Readable stream test</title>
    <script>
    function doRead() {
        let file = document.getElementById("file").files[0];
        let stream = file.stream();
        let reader = stream.getReader();
        let chunkId = 0;
        reader.read().then(function doChunk({value, done}) {
            if (done) {
                console.log("Read done.");
                return;
            }
            console.log("Chunk #" + chunkId + " (size = " + value.length + "):",
                        value);
            ++chunkId;
            return reader.read().then(doChunk);
        });
    }
    </script>
    </head>
    <body>
    <h1>Readable stream test</h1>
    <p>読み込むファイルを選択: <input type="file" id="file"></p>
    <p>読み込みを開始: <input type="button" value="Read" onclick="doRead()"></p>
    </body>
    </html>
    
    
[/code]


CC BY-SA 4.0
2020-07-30T12:45:32.697
69123
2020-07-30T12:45:32.697
40595
69121
answer


resultという変数を用意してonprogressのイベントが発生するたびに保存しておくのはどうでしょうか？  
また、この方法だとonprogressが発火するまでに15~25MB程度の文字列を読み込みます。これは5秒程度で読み込める大きさになります。

[code]

        <script>
            // <input type="file" id="file"/>を想定
            var file = document.getElementById('file');
            // File APIに対応しているか確認
            if(window.File && window.FileReader && window.FileList && window.Blob) {
                function loadLocalImage(e) {
                    var fileReader = new FileReader();
                    var fileData = e.target.files[0];
                    let result = []
                    fileReader.onprogress = ( event )=>{
                        //ここで途中経過を保持
                        result.push(event.target.result)
                        if ( event.loaded > 100000 )
                            fileReader.abort();
                    }
                    fileReader.onabort = ( event )=>{
                        //resultに途中まで読み込んだデータが配列で格納されている
                        //joinすることで配列から文字列になる
                        //これが中断した場合のそれまでに読み込んだ成果物
                        console.log(result.join("\n"))
                    }
                    fileReader.onload = (event)=>{
                        console.log(result.join("\n"))
                    }
                    fileReader.readAsText( e.target.files[0] );
                }
                file.addEventListener('change', loadLocalImage, false);
            }
        </script>
    
[/code]


CC BY-SA 4.0
2020-07-30T13:02:02.843
69124
2020-07-30T13:20:15.860
2020-07-30T13:20:15.860
41318
41318
69121
answer