How to read a local file in Javascript (Running from an Electron App)

Viewed 4981

I have been searching for over an hour or so, and I cant find an answer to my question. Is there a way to get the text from a local file, using just a plain old file URL?

I have found numerous ways to read a file via file input HTML tag, but I have had an incredible pain, finding a code example that can find a file, on my PC, using just plain old JS.

The code will be inside an electron application.

I need code examples. Something like this:

readFile("file:\\\\C:\path\to\file.txt","text/plain");

readFile(url,mimetype){
 ....
}
3 Answers

If you want to read a file in Electron, you have to understand the various parts of an Electron app. In short, there is a main process and a renderer process. The main process has and is given all control to use node modules, such as the fs module that can read files. The renderer process should not have access to the fs module, but instead anytime it needs to use the fs module, it should ask the main process to use fs, and then return the result.

FYI the renderer process is the web page, the visible part of your Electron app.

This communication is called IPC (inter-process communication). The flow is:

  1. Renderer process sends a message to the main process over IPC
  2. The main process hears the message, and then reads a file with fs
  3. The contents/result are sent back via IPC to the renderer process
  4. The renderer process now can do what it wants with the data from the file

A very rough example is below.

index.html

<!doctype html>
<html lang="en-US">
<head>
    <meta charset="utf-8"/>
    <title>Title</title>
</head>
<body>
    <script>
        // Called when message received from main process
        window.api.receive("fromMain", (data) => {
            console.log(`Received ${data} from main process`);
        });

        // Send a message to the main process
        window.api.send("toMain", "some data");
    </script>
</body>
</html>

main.js

const {
  app,
  BrowserWindow,
  ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;

async function createWindow() {

  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // is default value after Electron v5
      contextIsolation: true, // protect against prototype pollution
      enableRemoteModule: false, // turn off remote
      preload: path.join(__dirname, "preload.js") // use a preload script
    }
  });

  // Load app
  win.loadFile(path.join(__dirname, "dist/index.html"));

  // rest of code..
}

app.on("ready", createWindow);

ipcMain.on("toMain", (event, args) => {
  fs.readFile("path/to/file", (error, data) => {
    // Do something with file contents

    // Send result back to renderer process
    win.webContents.send("fromMain", responseObj);
  });
});

preload.js

const {
    contextBridge,
    ipcRenderer
} = require("electron");

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
    "api", {
        send: (channel, data) => {
            // whitelist channels
            let validChannels = ["toMain"];
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, data);
            }
        },
        receive: (channel, func) => {
            let validChannels = ["fromMain"];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender` 
                ipcRenderer.on(channel, (event, ...args) => func(...args));
            }
        }
    }
);

DISCLAIMER: I'm the author of a popular secure electron template, and have wrote a specific guide on how to use fs to read a file in an Electron app. I hope you give it a read because it has additional information there.

  1. Reading a file is done using node and is not dependent on electron
  2. Where you have the code for creating a window add this code
const fs = require("fs");

function readFile(fileURL,mimeType){
   //readfile does not accept the file:\\\ thing, so we remove it
   const pathToFile = fileURL.replace("file:\\\\",'');

   fs.readFile(pathToFile,mimeType,(err,contents)=>{
     if(err){
        console.log(err);
        return;
     }
     console.log(contents);
   })
}

readFile('C:\\Users\\<userAccount>\\Documents\\test.txt','utf8')
//If your on windows you'll need to use double backslashes for the paths
//here's an example regex to do that

pathToFile = pathToFile.replace(/\\/,'\\\\')

if im not mistaken, using something like this should work with the fs module.

fs.readFileSync("/path/to/file.txt");
Related