JavaScript fetch関数で巨大ファイルの部分的な読み込み
fetch( URL )だと全ファイルを読み込んでしまうため、追加のオプション設定でファイル情報を取得、部分的な読み込みを行う方法です。基本的な情報は無料、実践的な情報とソースコードは有料です。
XMLHttpRequestなどの必要な知識があれば簡単に実装できるのですが、知らなかった私は、情報が見つからず結局実装するのに1年ほどかかりました。探し方が悪いのか必要とされていないのか。
※開発環境 Windows10/11 Edge/Chrome
※OS/ブラウザによって動作が異なる可能性あり
実装する機能
ファイル情報の取得
ファイルの部分読み込み
ファイル情報の取得
fetchのoption設定に {method:"HEAD"}
レスポンスのheadersで様々なファイル情報が取得可能です。
let resp = await fetch(url,{method:"HEAD"});
// ファイルサイズ
let length = resp.headers.get("Content-Length");
// 部分的なアクセスに対応?
let range = resp.headers.get("Accept-Ranges");
// range == "bytes"
// 日時 ファイルタイプ
let date = resp.headers.get("Last-Modified");
let ctype = resp.headers.get("Content-Type");
ファイルの部分読み込み
fetchのoption.headersとHeadersクラスを使用します
// 100~200の100byte読み込み
let begin = 100;
let end = 200;
let headers = new Headers();
headers.append( "range", "bytes=" + begin + "-" + (end-1) );
let read = await fetch(url,{headers});
let buff = await read.arrayBuffer();
動作確認
Windows10/11 Edgeの開発者ツール(ネットワーク)で確認
fetch(url)での全ファイル読み込み
ファイル情報取得での通信データサイズ
部分読み込みでの通信データサイズ
有料 ファイル読み込みクラス
記事が役に立った!すぐに使えるソースコードがほしい!
という方は、記事の購入をお願いします。
fetch関数を利用したファイル読み込みクラスのソースコードです。
ファイルオープン、ファイル情報取得、部分的な読み込み、基本的なエラー処理(単純なthrow処理)
class FetchFile{
size : number; // ファイルサイズ
dateModify : Date; // 更新日時
type : string; // Content Type
// ファイルオープン
// ファイル情報の取得可能に サイズなど
async open(url : string);
// ファイルの部分読み込み begin ~ end-1
// ret : fetch Response
async read(begin : number, end : number);
async arrayBuffer(begin : number, end : number){
let r = await this.read(begin, end);
return r.arrayBuffer();
}
async blob(begin : number, end : number){
let r = await this.read(begin, end);
return r.blob();
}
// error -> throw "error text"
}
class FetchFile{
url : string;
size : number;
status : string;
dateModify : Date;
type : string;
constructor(){
this.url = "";
this.size = 0;
this.status = "null";
this.type = "";
this.dateModify = new Date();
}
// ファイルオープン
// ファイル情報の取得 サイズなど
async open(url : string){
// ファイル情報取得
let resp = await fetch(url,{method:"HEAD"});
this.url = "";
this.size = 0;
this.type = "";
if(!resp.ok){
throw "FetchFile Response " + resp.status;
}
if(resp.status != 200){
throw "FetchFile " + resp.status;
}
let length = resp.headers.get("Content-Length");
let range = resp.headers.get("Accept-Ranges");
let date = resp.headers.get("Last-Modified");
let ctype = resp.headers.get("Content-Type");
if(length === null || range ===null || date==null || ctype==null){
throw "FetchFile Header " + resp.status;
}
if(range != "bytes"){
throw "FetchFile Accept-Ranges" + resp.status;;
}
let size = parseInt(length);
if(isNaN(size)){
throw "FetchFile Content-Length" + resp.status;;
}
this.type = ctype;
this.url = url;
this.size = size;
this.status = "open";
this.dateModify = new Date(date);
}
// ファイルの部分読み込み begin ~ end-1
// ret : fetch Response
async read(begin : number, end : number){
if(this.status != "open"){
throw "FetchFile open";
}
let headers = new Headers();
if(begin < 0)begin = 0;
if(end < 1){
throw "FetchFile range " + begin + " " + end;
}
headers.append("range","bytes="+begin + "-" + (end-1));
let r = await fetch(this.url,{headers});
if(!r.ok){
throw "FetchFile Response";
}
if(r.status != 206){
throw "FetchFile " + r.status;
}
return r;
}
async arrayBuffer(begin : number, end : number){
let r = await this.read(begin, end);
return r.arrayBuffer();
}
async blob(begin : number, end : number){
let r = await this.read(begin, end);
return r.blob();
}
}
この記事が役に立ったという方は、サポートお願いします。今後の製作の励みになります。