archive用の処理を追加する

This commit is contained in:
ry.yamafuji 2025-03-21 00:57:41 +09:00
parent ecf620d6ac
commit 37ba3e8532
6 changed files with 248 additions and 26 deletions

View File

@ -1,6 +1,17 @@
# [Node.js]ファイルをZIP圧縮してダウンロードする方法 # [Node.js]ファイルをZIP圧縮してダウンロードする方法
- [\[Node.js\]ファイルをZIP圧縮してダウンロードする方法](#nodejsファイルをzip圧縮してダウンロードする方法)
- [圧縮処理について](#圧縮処理について)
- [方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)](#方法1フロンサイドで圧縮データを処理しファイルを保存するjszip)
- [方法2:サーバサイドで圧縮処理しファイルを出力する](#方法2サーバサイドで圧縮処理しファイルを出力する)
- [方法3:サーバサイドで圧縮処理しフロントでBlobによりファイルを取得する](#方法3サーバサイドで圧縮処理しフロントでblobによりファイルを取得する)
- [サンプルソース](#サンプルソース)
- [Blobを使用してZIPファイルを処理する(フロント側の処理)\*\*](#blobを使用してzipファイルを処理するフロント側の処理)
- [gcloudにあるファイルをzip形式でファイルを出力するサンプルソース](#gcloudにあるファイルをzip形式でファイルを出力するサンプルソース)
- [Zipダウンロードサーバを構築する(gcloud + express)](#zipダウンロードサーバを構築するgcloud--express)
## 圧縮処理について ## 圧縮処理について
* 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip) * 方法1:フロンサイドで圧縮データを処理しファイルを保存する(JSZip)
@ -113,7 +124,7 @@ fetch("https://example.com/sample.zip")
``` ```
#### Gloudにあるファイルをzip形式でファイルを出力するサンプルソース #### gcloudにあるファイルをzip形式でファイルを出力するサンプルソース
(スクリプト) (スクリプト)
```js ```js
@ -154,3 +165,46 @@ async function downloadAndZip() {
downloadAndZip().catch(console.error); downloadAndZip().catch(console.error);
``` ```
#### Zipダウンロードサーバを構築する(gcloud + express)
(サーバ)
```js
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}`);
});
```

View File

@ -0,0 +1,72 @@
/**
* @description downloadボタンを押下したらCSVファイルをzip圧縮してダウンロードする
*/
// ダウンロードボタン
const downloadButtonServer = document.getElementById('download-button-server');
// ダウンロードボタンを押下した時の処理を記載する
downloadButtonServer.addEventListener('click', async () => {
// Blobで取得する方法
console.log('downloadButtonServer');
// ダウンロードボタンを無効化する
downloadButtonServer.disabled = true;
// ダウンロード処理を実行する
try {
// localhost:3000/downdload にリクエストを送る
const response = await fetch('http://localhost:3000/downdload');
if (!response.ok) throw new Error('Failed to fetch');
// ZIPファイルを取得
const zipBlob = await response.blob();
const a = document.createElement("a");
a.href = URL.createObjectURL(zipBlob);
a.download = "serverFile.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
} finally {
// ダウンロードボタンを有効化する
downloadButtonServer.disabled = false;
}
});
// ダウンロードボタン(アップロード)
const downloadButtonUpload = document.getElementById('download-button-upload');
// ダウンロードボタンを押下した時の処理を記載する
downloadButtonUpload.addEventListener('click', async () => {
console.log('downloadButtonUpload');
// ダウンロードボタンを無効化する
downloadButtonUpload.disabled = true;
// サーバーにアップロード処理APIを送信する
try {
// localhost:3000/generate-zip にリクエストを送る
const response = await fetch('http://localhost:3000/generate-zip');
if (!response.ok) throw new Error('Failed to fetch');
// レスポンスからURLを取得
const { url } = await response.json();
// 取得したURLを開く
window.open(url);
} catch (e) {
// エラーが発生した場合
console.error(e);
alert('ダウンロードに失敗しました');
} finally {
// ダウンロードボタンを有効化する
downloadButtonUpload.disabled = false;
}
});

View File

@ -11,6 +11,10 @@
<p >Zip File Download</p> <p >Zip File Download</p>
<button id="download-button">Zip Download(From Content)</button> <button id="download-button">Zip Download(From Content)</button>
<button id="download-button-file">Zip Download(From File)</button> <button id="download-button-file">Zip Download(From File)</button>
<p >Server </p>
<button id="download-button-server">Zip Download(From Server)</button>
<button id="download-button-upload">Zip Download(upload)</button>
<script src="assets/download.js"></script> <script src="assets/download.js"></script>
<script src="assets/downloadFromServer.js"></script>
</body> </body>
</html> </html>

View File

@ -1,22 +0,0 @@
/**
* ZIPファイルを作成してダウンロードサーバ
*
* @description
* - ZIPファイルを作成してダウンロードするサーバー
* - Node.js + Express + archiver
*/
const express = require("express");
const fs = require("fs");
const path = require("path");
const archiver = require("archiver");
const app = express();
const PORT = 3000;
app.get("/download-zip", async (req, res) => {
});
// ZIPのダウンロード用エンドポイント
app.use(express.static(__dirname));
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

View File

@ -0,0 +1,91 @@
const archiver = require('archiver');
const fs = require('fs');
const path = require('path');
/**
* サーバサイドで圧縮処理しフロントエンドにファイルコンテンツを返す
* @param {http.IncomingMessage} req
* @param {http.ServerResponse} res
* @returns {void}
*/
const downdloadContents = (req, res) => {
// ファイルの圧縮処理
// CORSヘッダーを追加
res.setHeader('Access-Control-Allow-Origin', '*'); // すべてのオリジンを許可
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
// CSVファイル対象
const csvFilePaths = [
"./src/front/assets/data/test_data_1.csv",
"./src/front/assets/data/test_data_2.csv"
]
res.setHeader('Content-Type', 'application/zip');
res.setHeader('Content-Disposition', 'attachment; filename=test.zip');
const archive = archiver('zip', { zlib: { level: 9 } });
archive.on('error', (err) => {
console.error('Archiver Error:', err);
res.statusCode = 500;
res.end('Internal Server Error');
});
// レスポンスに直接圧縮データを送る
archive.pipe(res);
// ZIPにファイルを追加
csvFilePaths.forEach((filePath) => {
if (fs.existsSync(filePath)) {
archive.append(fs.createReadStream(filePath), { name: path.basename(filePath) });
} else {
console.warn(`File not found: ${filePath}`);
}
});
// ZIPファイルを作成
archive.finalize();
}
/**
* generateZipUrl
*
* @param {http.IncomingMessage} req
* @param {http.ServerResponse} res
*/
const generateZipUrl = (req, res) => {
// CORSヘッダーを追加
res.setHeader('Access-Control-Allow-Origin', '*'); // すべてのオリジンを許可
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Content-Type', 'application/json');
// CSVファイル対象
const csvFilePaths = [
"./src/front/assets/data/test_data_1.csv",
"./src/front/assets/data/test_data_2.csv"
]
// ZIPファイルを生成してファイルを保存する
const archive = archiver('zip', { zlib: { level: 9 } });
const zipFilePath = './src/front/assets/data/test.zip';
const output = fs.createWriteStream(zipFilePath);
archive.pipe(output);
// ZIPにファイルを追加
csvFilePaths.forEach((filePath) => {
if (fs.existsSync(filePath)) {
archive.append(fs.createReadStream(filePath), { name: path.basename(filePath) });
} else {
console.warn(`File not found: ${filePath}`);
}
});
// ZIPファイルを作成
archive.finalize();
// レスポンスにはURLを返す(~/assets/data/test.zip)
const url = `assets/data/test.zip`;
res.end(JSON.stringify({ url: url }));
}
module.exports = downdloadContents;
module.exports = generateZipUrl;

View File

@ -1,9 +1,32 @@
const http = require('http'); const http = require('http');
// download/download.jsのdowndloadContentsメソッドをインポート
const downdloadContents = require('./download/download');
// download/download.jsのgenerateZipUrlメソッドをインポート
const generateZipUrl = require('./download/download');
/**
* Create a new HTTP server
*/
const server = http.createServer((req, res) => { const server = http.createServer((req, res) => {
// Set the response HTTP header with HTTP status and Content type
// root path
if (req.url === '/') {
res.statusCode = 200; res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain'); res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n'); res.end('Hello World\n');
} else if (req.url === '/downdload') {
// ZIPファイルのコンテンツをそのまま返す
downdloadContents(req, res);
} else if (req.url === '/generate-zip') {
// ZIPファイルの生成してストレージのURLを返す
generateZipUrl(req, res);
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Not Found\n');
}
}); });
const port = 3000; const port = 3000;