Electron 项目来实现文件下载和上传功能(AI)
首先,我们需要初始化项目并安装必要的依赖:
npm init -y
npm install electron electron-builder --save-dev
接下来,让我们创建项目的基本文件结构:
- 首先创建
main.js
文件,这是 Electron 主进程的入口文件:
const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');
const fs = require('fs');
const https = require('https');
const http = require('http');let mainWindow;function createWindow() {mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js'),nodeIntegration: false,contextIsolation: true,},});mainWindow.loadFile('index.html');mainWindow.on('closed', () => {mainWindow = null;});
}app.whenReady().then(createWindow);app.on('window-all-closed', () => {if (process.platform !== 'darwin') {app.quit();}
});app.on('activate', () => {if (mainWindow === null) {createWindow();}
});// 文件下载功能
ipcMain.handle('download-file', async (event, { url, fileName }) => {try {const result = await dialog.showSaveDialog(mainWindow, {defaultPath: fileName,});if (result.canceled) {return { success: false, message: '用户取消了下载' };}const filePath = result.filePath;return new Promise((resolve) => {try {// Determine which protocol module to use based on the URLconst protocol = url.startsWith('https:') ? https : url.startsWith('http:') ? http : null;if (!protocol) {resolve({ success: false, message: '不支持的协议,仅支持 HTTP 和 HTTPS' });return;}protocol.get(url, (response) => {const file = fs.createWriteStream(filePath);response.pipe(file);file.on('finish', () => {file.close();resolve({ success: true, filePath });});file.on('error', (err) => {fs.unlink(filePath, () => {});resolve({ success: false, message: err.message });});}).on('error', (err) => {resolve({ success: false, message: err.message });});} catch (error) {resolve({ success: false, message: error.message });}});} catch (error) {return { success: false, message: error.message };}
});// 文件上传功能
ipcMain.handle('upload-file', async (event) => {try {const result = await dialog.showOpenDialog(mainWindow, {properties: ['openFile'],filters: [{ name: '所有文件', extensions: ['*'] }]});if (result.canceled || result.filePaths.length === 0) {return { success: false, message: '用户取消了上传' };}const filePath = result.filePaths[0];const fileName = path.basename(filePath);const fileContent = fs.readFileSync(filePath);// 这里是上传示例,实际应用中应该替换为实际的上传逻辑// 例如使用 axios 或 fetch 发送到服务器// 模拟上传成功return { success: true, fileName, filePath, fileSize: fileContent.length };} catch (error) {return { success: false, message: error.message };}
});
- 创建
preload.js
文件,用于在主进程和渲染进程之间建立安全的通信通道:
const { contextBridge, ipcRenderer } = require('electron');contextBridge.exposeInMainWorld('electronAPI', {downloadFile: (params) => ipcRenderer.invoke('download-file', params),uploadFile: () => ipcRenderer.invoke('upload-file')
});
- 创建
index.html
文件,这是应用的主界面:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Electron 文件上传下载示例</title><style>body {font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;margin: 40px;text-align: center;}.container {max-width: 600px;margin: 0 auto;}h1 {color: #333;}.form-group {margin-bottom: 20px;text-align: left;}label {display: block;margin-bottom: 5px;font-weight: 500;}input, button {width: 100%;padding: 10px;border: 1px solid #ddd;border-radius: 4px;font-size: 16px;box-sizing: border-box;}button {background-color: #4CAF50;color: white;border: none;cursor: pointer;margin-top: 10px;}button:hover {background-color: #45a049;}.upload-btn {background-color: #2196F3;}.upload-btn:hover {background-color: #0b7dda;}#status {margin-top: 20px;padding: 10px;border-radius: 4px;background-color: #f5f5f5;min-height: 20px;}.success {color: green;}.error {color: red;}</style>
</head>
<body><div class="container"><h1>Electron 文件上传下载示例</h1><div class="form-group"><label for="download-url">下载文件 URL:</label><input type="text" id="download-url" placeholder="请输入文件的下载链接"><button id="download-btn">下载文件</button></div><div class="form-group"><label for="file-name">保存的文件名:</label><input type="text" id="file-name" placeholder="请输入要保存的文件名"></div><div class="form-group"><button id="upload-btn" class="upload-btn">上传文件</button></div><div id="status"></div></div><script>document.getElementById('download-btn').addEventListener('click', async () => {const url = document.getElementById('download-url').value;const fileName = document.getElementById('file-name').value || 'downloaded-file';const statusElement = document.getElementById('status');if (!url) {statusElement.textContent = '请输入文件的下载链接';statusElement.className = 'error';return;}statusElement.textContent = '正在下载...';statusElement.className = '';try {const result = await window.electronAPI.downloadFile({ url, fileName });if (result.success) {statusElement.textContent = `文件下载成功: ${result.filePath}`;statusElement.className = 'success';} else {statusElement.textContent = `下载失败: ${result.message}`;statusElement.className = 'error';}} catch (error) {statusElement.textContent = `发生错误: ${error.message}`;statusElement.className = 'error';}});document.getElementById('upload-btn').addEventListener('click', async () => {const statusElement = document.getElementById('status');statusElement.textContent = '请选择要上传的文件...';statusElement.className = '';try {const result = await window.electronAPI.uploadFile();if (result.success) {statusElement.textContent = `文件上传成功: ${result.fileName} (${(result.fileSize / 1024).toFixed(2)} KB)`;statusElement.className = 'success';// 在实际应用中,这里可以添加更多的上传后处理逻辑} else {statusElement.textContent = `上传失败: ${result.message}`;statusElement.className = 'error';}} catch (error) {statusElement.textContent = `发生错误: ${error.message}`;statusElement.className = 'error';}});</script>
</body>
</html>
- 更新
package.json
文件,添加启动脚本和应用信息:
{"name": "electron-file-transfer","version": "1.0.0","description": "Electron 文件上传下载示例应用","main": "main.js","scripts": {"start": "electron .","build": "electron-builder"},"keywords": ["electron", "file", "upload", "download"],"author": "Your Name","license": "MIT","devDependencies": {"electron": "^25.0.0","electron-builder": "^24.6.3"},"build": {"appId": "com.example.electronfiletransfer","productName": "Electron文件传输","win": {"target": "nsis","icon": "build/icon.ico"},"mac": {"target": "dmg","icon": "build/icon.icns"},"linux": {"target": "AppImage"}}
}
现在,项目的基本文件已经创建完成。让我们创建一个 .gitignore
文件(如果需要的话):
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*node_modules
dist
dist-ssr
*.local# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
项目创建完成后,您可以通过以下命令运行应用:
npm start
如果需要打包应用,可以使用:
npm run build
这个 Electron 应用实现了以下功能:
-
文件下载:用户可以输入文件的 URL 和保存的文件名,点击下载按钮后,应用会通过 Electron 的对话框让用户选择保存位置,然后下载文件。
-
文件上传:用户点击上传按钮后,应用会弹出文件选择对话框,用户选择文件后,应用会读取文件内容并模拟上传过程。在实际应用中,您需要将模拟上传的部分替换为实际的服务器上传逻辑。
这个项目使用了 Electron 的现代安全实践,如 contextIsolation 和 preload.js,确保了应用的安全性。