トップページ -> 大きいファイルを圧縮・分割してレンタルサーバーにアップロードする方法

大きいファイルを圧縮・分割してレンタルサーバーにアップロードする方法

アナグラム自動解析(日本語)などを行うときには事前に用意された大きなファイルが必要になることがあります. 日本語のアナグラムを解くのに必要だった単語の辞書は70MBほどあったのですが,Xfreeのレンタルサーバーにアップロードすることのできるファイルサイズの上限は2MBでしたので,ファイルを35分割するかファイルサイズを大きく削減する必要がありました. ここではJavascriptで利用したいjsonやcsvなどのファイルサイズを削減して利用する方法を紹介します. 70MBの辞書を18MB程度まで削減することができました.
【参考(外部サイト)】JavaScript でデータを Deflate (Zlib, Gzip) 圧縮および解凍する
【関連ページ】バイナリーエンコーダー json, csvファイルなどの圧縮

ファイルサイズの削減

JavaScript でデータを Deflate (Zlib, Gzip) 圧縮および解凍するで紹介されている方法を使って文字列を圧縮することでファイルサイズを削減します. 今回は文字列の変換ではなくファイルを読み込んで変換したいので,ファイルを読み込む部分を追加しました. htmlに <input type="file" id="fileInput" onchange="readFile()"> を書いてファイルを受け取れるようにします. ファイルを受け取った後にmain()を走らせることで変換・ダウンロードができます. バイナリーエンコーダー json, csvファイルなどの圧縮で以下のコードのような圧縮をすることができます.


<script>
    // JavaScript でデータを Deflate (Zlib, Gzip) 圧縮および解凍する(https://qiita.com/kerupani129/items/6c75af041c89d2a7f2f5)を参考
    const gzip = async data => {
        const readableStream = new Blob([data]).stream();
        const compressedStream = readableStream.pipeThrough(
            // メモ: 毎回インスタンス化する必要がある
            new CompressionStream('gzip'),
        );
        const arrayBuffer = await new Response(compressedStream).arrayBuffer();
        return arrayBuffer;
    };

    const ungzip = async data => {
        const readableStream = new Blob([data]).stream();
        const decompressedStream = readableStream.pipeThrough(
            // メモ: 毎回インスタンス化する必要がある
            new DecompressionStream('gzip'),
        );
        const arrayBuffer = await new Response(decompressedStream).arrayBuffer();
        return arrayBuffer;
    };

    // ファイルの読み込み
    textA = ""
    function readFile() {
        const fileInput = document.getElementById('fileInput');

        const selectedFile = fileInput.files[0];
        const reader = new FileReader();

        reader.onload = function(event) {
            textA = event.target.result;
        };

        reader.readAsText(selectedFile); // テキストファイルとして読み込む
    }

    function main() {
        const textUint8ArrayA = new TextEncoder().encode(textA);

        // 圧縮
        // メモ: gzip 関数に直接 textA を渡すことも可
        const arrayBufferA = await gzip(textUint8ArrayA);

        // Blobを作成
        const blob = new Blob([arrayBufferA], { type: 'application/octet-stream' });
        // ダウンロード用のURLを作成
        const downloadLink = document.createElement('a');
        downloadLink.href = window.URL.createObjectURL(blob);
        downloadLink.download = fileName; // ダウンロード時のファイル名

        // リンクをクリックしてダウンロードを開始
        downloadLink.click();
    }
</script>

ファイルの読み込み

サーバー上にアップロードしたファイルのURLを入力し,バイナリーデータを読み込みます. 以下は3つに分割されたファイルを読み込んで文字列をdataに格納していくコードです.


const gzip = async data => {
    const readableStream = new Blob([data]).stream();
    const compressedStream = readableStream.pipeThrough(
        // メモ: 毎回インスタンス化する必要がある
        new CompressionStream('gzip'),
    );
    const arrayBuffer = await new Response(compressedStream).arrayBuffer();
    return arrayBuffer;
};

const ungzip = async data => {
    const readableStream = new Blob([data]).stream();
    const decompressedStream = readableStream.pipeThrough(
        // メモ: 毎回インスタンス化する必要がある
        new DecompressionStream('gzip'),
    );
    const arrayBuffer = await new Response(decompressedStream).arrayBuffer();
    return arrayBuffer;
};

// サーバー上のファイルを取得する関数
dataNum = 3
data = new Array(dataNum).fill(0)
async function getFileFromServer(i) {
    try {
        // サーバー上のファイルのURL
        const fileUrl = 'http://????/????/file_from_js' + i + '.bin'; // ここにファイルのURLを入力

        const response = await fetch(fileUrl);
        
        if (!response.ok) {
        throw new Error('Network response was not ok');
        }
        
        const arrayBufferA = await response.arrayBuffer();
        
        // ここで arrayBufferA を使って処理を行う
        const arrayBufferB = await ungzip(arrayBufferA);
        const textB = new TextDecoder().decode(arrayBufferB);
        data[i] = textB
    } catch (error) {
        console.error('Error fetching file:', error);
    }
}

// getFileFromServer()を実行してサーバー上のファイルを取得
for (i=1;i<dataNum+1;i++) {
    getFileFromServer(i);
}

データの形式に合わせてパースする

jsonやcsvなどのデータの形式に合わせてパースします. dataに格納されている文字列を結合し,必要に応じてparseします. jsonであれば以下のようにparseできます.


text = ""
for (i=1;i<dataNum;i++) {
    text += data[i]
}

jsonData = JSON.parse(text)