7.8 KiB
7.8 KiB
[Node.js]ファイルをZIP圧縮してダウンロードする方法
圧縮処理について
- 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
- 方法2:サーバサイドで圧縮処理しファイルを出力する
- 方法3:サーバサイドで圧縮処理しフロントでBlobによりファイルを取得する
方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
- ファイル量が多い場合(30MB以上など)はサーバーサイドで処理するほうがいい
- 大容量データの処理には向かない
- ユーザーのデバイスの性能に依存する
sequenceDiagram
User->>Front: ダウンロードボタンを要求する
loop ファイル毎に処理する
Front->>Storage: ファイルを要求する(fetch)
Storage-->>Front: ファイル情報を返す
end
Front-->>Front: Zip処理を実行する(JSZip)
Front-->>User: ダウンロード処理を実行する(blob)
import JSZip from "jszip";
CDNでインポートする場合
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
方法2:サーバサイドで圧縮処理しファイルを出力する
サーバーサイドでarchiverを使ってZIPを作成し、 一時ファイルとして保存してからダウンロード用のURLを返します
- archiverモジュールで実行する
- Zipファイルの保存のためにストレージが別で必要
- ライフサイクルを考慮しないと不要なファイルが溜まる
- 大容量データの圧縮に適してい
- 複数のリクエストに対応しやすい
sequenceDiagram
User->>Front: ダウンロードボタンを要求する
Front->>Server: ダウンロードを要求する
Server->>Storage: ファイルデータ取得API
Storage->>Server: レスポンス
Server->>Server: Zip処理を実行する(archiver)
Server->>Storage: 作成した Zipを保存する
Storage->>Server: レスポンス
Server-->>Front: ファイルのURLを返す
Front->>Storage: URLをリンクする(HTTP)
Storage-->>User: ファイルをダウンロードする
npm install archiver
方法3:サーバサイドで圧縮処理しフロントでBlobによりファイルを取得する
ZIPを一時ファイルとして保存せずに 直接フロントエンドにストリームとして送信します。
- archiverモジュールで実行する
- 保存せずにファイルコンテンツを返す
- リアルタイムでファイルをストリーミング可能
- ストレージの管理が不要
- クライアントがダウンロードを途中でキャンセルするとデータが失われる可能性がある
sequenceDiagram
User->>Front: ダウンロードボタンを要求する
Front->>Server: ダウンロードを要求する
Server->>Storage: ファイルデータ取得API
Storage->>Server: レスポンス
Server->>Server: Zip処理を実行する(archiver)
Storage->>Front: Zipされたファイルコンテンツを返す
Front-->>User: ダウンロード処理を実行する(blob)
サンプルソース
Blobを使用してZIPファイルを処理する(フロント側の処理)**
fetch("https://example.com/sample.zip")
.then(response => response.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "downloaded.zip";
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
})
.catch(error => console.error("Error downloading ZIP:", error));
gcloudにあるファイルをzip形式でファイルを出力するサンプルソース
(スクリプト)
const { Storage } = require('@google-cloud/storage');
const archiver = require('archiver');
const fs = require('fs');
const storage = new Storage();
const bucketName = 'your-bucket-name';
const filesToDownload = ['file1.csv', 'file2.csv']; // 圧縮したいファイルリスト
const outputZip = 'output.zip';
async function downloadAndZip() {
const output = fs.createWriteStream(outputZip);
const archive = archiver('zip', { zlib: { level: 9 } });
output.on('close', () => {
console.log(`Zip file created: ${outputZip} (${archive.pointer()} bytes)`);
});
archive.pipe(output);
for (const fileName of filesToDownload) {
const file = storage.bucket(bucketName).file(fileName);
const [exists] = await file.exists();
if (exists) {
console.log(`Adding ${fileName} to archive...`);
archive.append(file.createReadStream(), { name: fileName });
} else {
console.warn(`File not found: ${fileName}`);
}
}
archive.finalize();
}
downloadAndZip().catch(console.error);
Zipダウンロードサーバを構築する(gcloud + express)
(サーバ)
const { Storage } = require('@google-cloud/storage');
const express = require('express');
const archiver = require('archiver');
const storage = new Storage();
const bucketName = 'your-bucket-name';
const app = express();
const port = 3000;
app.get('/download-zip', async (req, res) => {
const filesToDownload = ['file1.csv', 'file2.csv']; // 圧縮したいファイルリスト
res.setHeader('Content-Type', 'application/zip');
res.setHeader('Content-Disposition', 'attachment; filename="compressed_files.zip"');
const archive = archiver('zip', { zlib: { level: 9 } });
archive.pipe(res); // レスポンスに直接圧縮データを送る
for (const fileName of filesToDownload) {
const file = storage.bucket(bucketName).file(fileName);
const [exists] = await file.exists();
if (exists) {
console.log(`Adding ${fileName} to archive...`);
archive.append(file.createReadStream(), { name: fileName });
} else {
console.warn(`File not found: ${fileName}`);
}
}
archive.finalize(); // ZIP 圧縮を完了
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});