ローカルファイルを読み書きできた。
ブツ
ファイルを読み込む
Open
ボタンを押す- 拡張子
txt
ファイルを選ぶ - 2のファイル内容がテキストエリアに表示される
ファイルを書き込む
- テキストエリアに適当なテキストを書く
Save
ボタンを押す- 入力したファイルに1の内容が書き込まれる
前回まで
インストール&実行
NAME='Electron.File.Read.Write.20220803171508'
git clone https://github.com/ytyaru/$NAME
cd $NAME
npm install
npm start
コード
package.json
{
...
"main": "main.js",
...
"devDependencies": {
"electron": "^19.0.9"
}
}
main.js
const fs = require('fs')
const path = require('path')
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
...
ipcMain.handle('open', async (event) => {
const { canceled, filePaths } = await dialog.showOpenDialog({
filters: [{ name: 'Documents', extensions: ['txt'] }],
})
if (canceled) return { canceled, data: [] }
const data = filePaths.map((filePath) =>
fs.readFileSync(filePath, { encoding: 'utf8' })
)
return { canceled, data }
})
ipcMain.handle('save', async (event, data) => {
const { canceled, filePath } = await dialog.showSaveDialog({
filters: [{ name: 'Documents', extensions: ['txt'] }],
})
if (canceled) { return }
fs.writeFileSync(filePath, data)
})
preload.js
const {remote,contextBridge,ipcRenderer} = require('electron');
...
contextBridge.exposeInMainWorld('myApi', {
setup: ()=>{
document.querySelector('#open').addEventListener('click', async () => {
console.debug(`openをclickした!`)
const { canceled, data } = await ipcRenderer.invoke('open')
if (canceled) { return }
document.querySelector('#text').value = data[0] || ''
})
document.querySelector('#save').addEventListener('click', async () => {
const data = document.querySelector('#text').value
await ipcRenderer.invoke('save', data)
})
},
})
renderer.js
window.myApi.setup();
index.html
<!DOCTYPE html>
<html>
...
<script src="./renderer.js"></script>
</body>
</html>
ポイント
- IPC通信
- ファイルダイアログUI
- ファイル読書
1. IPC通信
EelctronやNode.jsのようなブラウザ外機能はIPC通信を介して実行する。
IPC通信はプロセス間通信のこと。別プロセスで動作している別プログラムの間でデータ通信する。おそらくElectronがローカルシステム用プロセスと、HTML描画&JS実行エンジン用プロセスに分けることでセキュリティを保ちつつ、二者間でIPC通信することで、ローカルシステムにアクセスしながらHTMLやJSの機能も使えるようにしているのだろう。
ファイル | 内容 |
---|---|
main.js | ipcMain.handle で実装する |
preload.js | ipcRenderer.invoke で呼び出す |
IPC通信はEelctronでのお約束っぽい。バージョンが違うと作法も変わるかも。ブラウザ版のときとは明確にコードが異なり共通化できない部分。
このようなEelctron固有の部分で苦労させられる。ネットで調べてもバージョン差異により動作しないこともある。きっと今後もハマるだろう。
2. ファイルダイアログUI
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
...
const { canceled, filePaths } = await dialog.showOpenDialog({
filters: [{ name: 'Documents', extensions: ['txt'] }],
})
electron
パッケージの中にdialog
がある。UI表示するAPIを呼び出す。
読込と書込で異なるAPIをもつ。
const { canceled, filePath } = await dialog.showSaveDialog({
filters: [{ name: 'Documents', extensions: ['txt'] }],
})
API | 概要 |
---|---|
showOpenDialog |
読込用ファイルダイアログ表示 |
showSaveDialog |
書込用ファイルダイアログ表示 |
3. ファイル読書
ファイルシステム操作用パッケージfs
を取り込む。
const fs = require('fs')
ファイル読込APIが以下。
const data = filePaths.map((filePath) =>
fs.readFileSync(filePath, { encoding: 'utf8' })
)
ファイル書込APIが以下。
fs.writeFileSync(filePath, data)
Electron用ドキュメントにfs
はなかった。Node.js用ドキュメントにfs
ドキュメントがあった。これでファイル操作するようだ。