📜  ElectronJS 中的文件上传

📅  最后修改于: 2022-05-13 01:56:54.250000             🧑  作者: Mango

ElectronJS 中的文件上传

ElectronJS是一个开源框架,用于使用能够在 Windows、macOS 和 Linux 操作系统上运行的HTMLCSSJavaScript等 Web 技术构建跨平台原生桌面应用程序。它将 Chromium 引擎和 NodeJS 组合成一个单一的运行时。

任何本机桌面应用程序都应将自身与系统操作系统环境集成。应用程序应该能够与核心操作系统功能进行交互,例如文件系统、系统托盘等。Electron 为我们提供了内置的对话框模块来显示与文件交互的本机系统对话框。本教程将使用对话框模块的实例方法来演示 Electron 中的文件上传功能。

我们假设您熟悉上述链接中涵盖的先决条件。为了使 Electron 正常工作,需要在系统中预先安装nodenpm

对话模块:对话模块是Main Process的一部分。要在渲染器进程中导入和使用对话框模块,我们将使用 Electron远程模块。

  • 项目结构:
    项目结构

示例:我们将首先按照给定的步骤构建用于文件上传功能的电子应用程序。

  • 第 1 步:导航到空目录以设置项目,然后运行以下命令,
    npm init

    生成package.json文件。使用 npm 安装Electron

    npm install electron --save

    这将安装所需的node_modules依赖项。使用 npm 安装axios包。

    npm install axios --save

    这个包是一个基于 Promise 的 NodeJS HTTP 客户端。此包用于对 REST API 进行 HTTP 调用。有关axios的更多详细信息,请参阅此链接。在assets文件夹中创建sample.txt文件以进行演示。

    包.json:

    {
      "name": "electron-fileupload",
      "version": "1.0.0",
      "description": "File Upload in Electron",
      "main": "main.js",
      "scripts": {
        "start": "electron ."
      },
      "keywords": [
        "electron"
      ],
      "author": "Radhesh Khanna",
      "license": "ISC",
      "dependencies": {
        "axios": "^0.19.2",
        "electron": "^8.2.5"
      }
    }
    
  • 第 2 步:这是main.js文件。对于main.js文件的样板代码,请参考此链接。我们已经修改了代码以满足我们的项目需求。

    主.js:

    const { app, BrowserWindow } = require('electron')
      
    function createWindow () {
      // Create the browser window.
      const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true
        }
      })
      
      // Load the index.html of the app.
      win.loadFile('src/index.html')
      
      // Open the DevTools.
      win.webContents.openDevTools()
    }
      
    // This method will be called when Electron has finished
    // initialization and is ready to create browser windows.
    // Some APIs can only be used after this event occurs.
    // This method is equivalent to 'app.on('ready', function())'
    app.whenReady().then(createWindow)
      
    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
      // On macOS it is common for applications and their menu bar
      // To stay active until the user quits explicitly with Cmd + Q
      if (process.platform !== 'darwin') {
        app.quit()
      }
    })
      
    app.on('activate', () => {
      // On macOS it's common to re-create a window in the  
      // app when the dock icon is clicked and there are no 
      // other windows open.
      if (BrowserWindow.getAllWindows().length === 0) {
        createWindow()
      }
    })
      
    // In this file, you can include the rest of your 
    // app's specific main process code. You can also 
    // put them in separate files and require them here.
    
  • 第三步:src目录下创建index.html文件和index.js文件。我们还将从上述链接复制index.html文件的样板代码。我们已经修改了代码以满足我们的项目需求。

    索引.html:

    
    
      
        
        Hello World!
        
        
      
      
        

    Hello World!

    We are using node      , Chrome      , and Electron      .        

    File Upload in Electron

                            
  • 输出:此时,我们的应用程序已设置好,我们可以启动应用程序来检查 GUI 输出。要启动 Electron 应用程序,请运行以下命令:
    npm start

  • 第 4 步:上传文件”按钮尚无任何相关功能。 dialog.showOpenDialog(browserWindow, options)接受以下参数。
    • browserWindow: BrowserWindow (可选) BrowserWindow实例。此参数允许对话框将自身附加到父窗口,使其成为modal 。模态窗口是禁用父窗口的子窗口。如果BrowserWindow未显示,对话框将不会附加到它。在这种情况下,它将显示为独立窗口。在上面的代码中, BrowserWindow实例没有被传递给对话框,因此对话框在单击Upload File按钮时作为独立窗口打开。
    • options: Object它接受以下参数,
      • title: String (可选)要在对话窗口上显示的标题。
      • defaultPath: String (可选)单击“上传文件”按钮时默认路径定义的要打开的目录。
      • buttonLabel:字符串(可选)确认按钮的自定义标签。如果为空,将使用默认标签。在上面的代码中,它被定义为Upload
      • message: String (可选)此参数仅在macOS中受支持。这用于在输入框上方显示自定义消息。
      • securityScopedBookmarks: Boolean (可选)此参数仅在macOS中受支持。此参数用于在为 Mac App Store 打包时创建安全范围的书签。有关更多详细信息,请参阅此链接。
      • filters: FileFilter[{}] (可选)它是一个对象数组。它定义了一个文件类型数组,当我们想要将用户限制为特定类型时可以显示或选择这些文件类型。我们可以定义属于不同类别的多个文件类型对象。 FileFilter 对象接受以下参数,
        • name: String扩展类别的名称。
        • extensions: [] extensions 数组应该由不带通配符或点的扩展组成,如代码中所示。要显示所有文件,请使用*通配符(不支持其他通配符)。有关更多详细信息,请参阅此链接。

        在上面的代码中,我们只想将用户限制为文本文件。因此,我们将名称定义为Text Files并将扩展数组定义为['txt', 'docx']

      • properties: String[] (可选)包含可用于本机对话框的功能列表。它采用以下值,
        • openFile:允许选择文件。
        • openDirectory:允许选择目录/文件夹。
        • multiSelections:允许在对话框中选择多个文件。
        • showHiddenFiles:在对话框中显示隐藏文件。
        • createDirectory:此值仅在macOS中受支持。它允许从对话框中创建新目录。在 Windows 中,上下文菜单在对话框中预先可用(在对话框窗口中单击鼠标右键) ,我们可以从中创建新文件和目录。
        • promptToCreate:此值仅在Windows中受支持。当对话框中输入的文件路径在系统上不存在时使用此值。这时候应该提示用户创建。这实际上不会在路径上创建文件,但允许返回不存在的路径,应用程序可以进一步创建和使用这些路径。
        • noResolveAliases:此值仅在macOS中受支持。它禁用将别名的文件路径自动解析为其原始目标。选定的别名现在将返回别名路径而不是它们的目标路径。
        • treatPackageAsDirectory:此值仅在macOS中受支持。它将诸如.app文件夹之类的包视为目录而不是文件。
        • dontAddToRecent:此值仅在Windows中受支持。此值表示不应将选择的文件/目录添加到最近的文档列表中。

        注意:根据 Electron 官方文档,在WindowsLinux操作系统中,打开的对话框不能同时是文件选择器和目录选择器。如果在这些平台上同时指定了两个属性['openFile', 'openDirectory'] ,将显示目录选择器,我们将无法选择文件。因此,在代码中,我们为win32/linuxdarwin平台指定了不同的对话框属性

    dialog.showOpenDialog(browserWindow, options)返回一个Promise 。它解析为包含以下参数的对象

    • cancelled: Boolean对话操作是否被取消。
    • filePaths: String[]用户选择的文件路径数组。如果对话操作被取消,它将是一个空数组。如果在properties中未提供multiSelections值,则 filePaths 数组将返回单个元素。
    • 书签:String[] (可选)此字符串数组仅在macOS中受支持。当在选项对象中将securityScopedBookmarks参数指定为true时,将返回此值。

      index.js:在该文件中添加以下代码段。

      const electron = require('electron');
      const path = require('path');
        
      // Importing dialog module using remote
      const dialog = electron.remote.dialog;
        
      var uploadFile = document.getElementById('upload');
        
      // Defining a Global file path Variable to store 
      // user-selected file
      global.filepath = undefined;
        
      uploadFile.addEventListener('click', () => {
      // If the platform is 'win32' or 'Linux'
          if (process.platform !== 'darwin') {
              // Resolves to a Promise
              dialog.showOpenDialog({
                  title: 'Select the File to be uploaded',
                  defaultPath: path.join(__dirname, '../assets/'),
                  buttonLabel: 'Upload',
                  // Restricting the user to only Text Files.
                  filters: [
                      {
                          name: 'Text Files',
                          extensions: ['txt', 'docx']
                      }, ],
                  // Specifying the File Selector Property
                  properties: ['openFile']
              }).then(file => {
                  // Stating whether dialog operation was
                  // cancelled or not.
                  console.log(file.canceled);
                  if (!file.canceled) {
                    // Updating the GLOBAL filepath variable 
                    // to user-selected file.
                    global.filepath = file.filePaths[0].toString();
                    console.log(global.filepath);
                  }  
              }).catch(err => {
                  console.log(err)
              });
          }
          else {
              // If the platform is 'darwin' (macOS)
              dialog.showOpenDialog({
                  title: 'Select the File to be uploaded',
                  defaultPath: path.join(__dirname, '../assets/'),
                  buttonLabel: 'Upload',
                  filters: [
                      {
                          name: 'Text Files',
                          extensions: ['txt', 'docx']
                      }, ],
                  // Specifying the File Selector and Directory 
                  // Selector Property In macOS
                  properties: ['openFile', 'openDirectory']
              }).then(file => {
                  console.log(file.canceled);
                  if (!file.canceled) {
                    global.filepath = file.filePaths[0].toString();
                    console.log(global.filepath);
                  }  
              }).catch(err => {
                  console.log(err)
              });
          }
      });
      

      输出:

    • 第 5 步:一旦我们从对话框窗口中获得了文件路径,我们可以采用以下两种方法中的任何一种:
      • 方法 1:通过 HTTP POST REST API 调用将文件上传到服务器,让服务器处理文件。我们将使用之前安装的axios包来实现这一点。
        index.js文件中,在console.log(global.filepath);之后添加以下代码}Promise
        index.js:
        const fs = require('fs');
        const axios = require('axios');
          
        if (global.filepath && !file.canceled) {
                 var formData = new FormData();
                 formData.append('file', fs.createReadStream(global.filepath));
                 axios.post('[Custom URL]', formData, {
                 headers: {
                    'Content-Type': 'multipart/form-data'
                   }
                }); 
              } 
          
        // ...
        

        说明:我们使用fs模块将文件附加到formData对象,并将 POST 请求的Content-Type标头设置为multipart/form-data 。将[Custom URL]替换为 REST API 的 URL,以在服务器端接收文件。一旦我们在服务器端收到文件,我们就可以让服务器处理文件并显示相应的响应。

      • 方法2:通过读取/操作文件的内容来处理系统本身的文件。我们可以使用fs模块读取文件的内容,然后根据需要执行进一步的操作。
        index.js文件中,在console.log(global.filepath);之后添加以下代码}Promise
        const fs = require('fs');
        const fs = require('fs');
          
        if (global.filepath && !file.canceled) {
          fs.readFile(global.filepath, {encoding: 'utf-8'}, function(err,data) {
             if (!err) {
                  console.log('received data: ' + data);
             } else {
                  console.log(err);
              }
           });
         }
          
        //...
        

        说明:我们将从使用标准UTF-8编码的对话窗口更新的 GLOBAL 文件路径变量中读取文件。一旦我们成功获取了文件的内容,我们就可以根据所需的功能更新/操作内容。

        示例.txt:
        样本.txt

        输出: