常識だからだと思うけど、Node.js始めたのでファイル入出力やろうとすると、割と動かないし、記事がもう一息なので、自分で整理しておこうと思う。
今回は、テキストファイル書き出し/読込とJsonファイルの書き出し/読込をやろうと思う。
参考は以下のとおり
【参考】
①Node.jsを使ったやっつけのファイル操作
②[Node.js]ファイルの作成、書き込み、追記をする
③JSのObjectをforEachで処理する方法
やったこと
・テキストファイル書き出し/読込
・Jsonファイル書き出し/読込
・テキストファイル書き出し/読込
これは、参考①で取り上げているので、まんま動くかなと思ったが、少し違うような気もしたので、参考②を見つつ、実際動かして以下のコードで動くことを確認した。
コード解説
まず、参考①と②を比較するとvarなのかconstなのか。。以下の参考④から、スコープが以下のとおりだということです。
なので、今回はconstで足りているようです。
【参考】
④var/let/constの使い分けのメモ
- var;
- 関数内のどこでもvarの宣言を書ける
- 関数のどこで宣言しても、先頭で定義したものとしてみなされる
- 関数スコープである
- 使いたい変数は先頭部分で全て定義するのが定石
- let;
- ブロックスコープ
- スコープを狭く出来るため影響範囲を狭められる
- const;
- 再代入不可能な変数を作る (つまり定数にできる)
- letと同じブロックスコープ
したがって、流動性に関しては、var>let>constの順に融通性があるようです。因みに以下の関数内のletはconstにするとisExistを変更している部分でエラーが出ます。
const fs = require('fs');
Node.jsの予約語を注意しつつ、以下のような関数名(参考⑥から関数の命名規則;関数名は先頭小文字のキャメルケース。例:sendMessage)にしました。
【参考】
⑤予約語
⑥JavaScriptの命名規則を現役エンジニアが解説【初心者向け】
以下がファイルの存在確認の関数です。
function checkFile(filePath) {
let isExist = false;
try {
fs.statSync(filePath);
isExist = true;
} catch(err) {
isExist = false;
}
return isExist;
}
以下は、ファイルにstreamを書き込む関数です。streamは文字列です。
function writeFile(filePath, stream) {
let result = false;
try {
fs.writeFileSync(filePath, stream);
return true;
} catch(err) {
return false;
}
}
以下がファイルの読み込み関数です。読み込まれた文字列がcontentに格納されリターンされます。
function readFile(filePath) {
let content = new String();
if(checkFile(filePath)) {;
content = fs.readFileSync(filePath, 'utf8');
}
return content;
};
以下がファイルを削除する関数です。
function delFile(filePath){
let result = false;
try {
fs.unlinkSync(filePath);
return true;
} catch(err) {
return false;
}
}
以下は既存ファイルにアペンドする関数です。
function addFile(filePath, stream) {
let result = false;
try {
fs.appendFileSync(filePath, stream);
return true;
} catch(err) {
return false;
}
}
ということで、以下で一連の関数を実行しています。
const check_result = checkFile("file_");
console.log("check_result", check_result)
const write_result = writeFile("file_", "aaa")
console.log("write_result", write_result)
const add_result = addFile("file_", "\n"+"bbb")
console.log("add_result", add_result)
const read_result = readFile("file_")
console.log("read_result",typeof(read_result))
console.log(read_result)
結果は以下のとおり、あんまりおもしろくはないけど、正しく実行できています。
ちなみに、read_resultはstr型です。
check_result true
write_result true
add_result true
read_result string
aaa
bbb
・Jsonファイル書き出し/読込
次は、利用度の高いと思われるJsonファイルの書き出し/読込をやります。参考③のまんまで、以下のコードで実行できます。
実は、まず以下の参考⑥をやりましたが、jsonObject.list.forEach((obj)
が動きませんでした。ということで参考③にたどり着きました。
【参考】
⑥Node.jsでJSONを読み込んで加工して書き出す
早速、動くコードを見てみます。
まず、参考⑥を動かします。以下は無事に読み込みました。
var obj = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log("jsonObject",obj)
結果は、以下のとおりで、Jsonファイルです。
jsonObject {
name: 'test-linebot',
version: '1.0.0',
description: '',
main: 'index.js',
scripts: { test: 'echo "Error: no test specified" && exit 1' },
keywords: [],
author: '',
license: 'ISC',
dependencies: {
'@line/bot-sdk': '^7.0.0',
express: '^4.17.1',
'node-tfidf': '0.0.2',
'tf-idf.js': '^0.3.2'
}
}
そして、参考③のコードも以下のように動きます。
// こういうオブジェクトがあったとしてね
var obj = { tanuki:'pon-poko', kitsune:'kon-kon', neko:'nyan-nyan' };
// こうすればOK
Object.keys(obj).forEach(function (key){
console.log(key + "は" + obj[key] + "と鳴いた!");
});
出力もコード(keyとobj[key]の内容)も見やすいです。
tanukiはpon-pokoと鳴いた!
kitsuneはkon-konと鳴いた!
nekoはnyan-nyanと鳴いた!
そして、以下でいよいよjsonファイルに書き出します。
const result = {};
Object.keys(obj).forEach(function(key){
result[key] = obj[key];
//console.log(key,obj[key])
});
fs.writeFileSync('output.json', JSON.stringify(result));
output.jsonファイルの中身は以下のとおりです。
{"tanuki":"pon-poko","kitsune":"kon-kon","neko":"nyan-nyan"}
次に、Jsonファイルの読み書きの関数を以下のように定義しました。
まず、読み込み関数は以下のとおりです。
function readJF(filePath) {
let content = {};
if(checkFile(filePath)) {;
content = JSON.parse(fs.readFileSync(filePath, 'utf8'));
}
return content;
};
次に、書込み関数は以下のとおりです。
Jsonファイルの追記のコードは、場合によりそうなので、適切なものが思いつきませんでした。一応、参考⑦にいくつかの例があります。
【参考】
⑦How do I add to an existing json file in node.js
function writeJF(filePath,obj) {
let result_ = false;
const result = {};
Object.keys(obj).forEach(function(key){
result[key] = obj[key];
//console.log(key,obj[key])
});
fs.writeFileSync(filePath, JSON.stringify(result));
result_ = true;
return result_;
};
最後に以下のとおり、実行してみました。
const readJ_result = readJF("package.json")
console.log("readJ_result",readJ_result)
console.log("readJ_result.name")
console.log(readJ_result['name'])
var writeJ_result = writeJF("test_.json",readJ_result)
結果は以下のとおりです。
readJ_result {
name: 'test-linebot',
version: '1.0.0',
description: '',
main: 'index.js',
scripts: { test: 'echo "Error: no test specified" && exit 1' },
keywords: [],
author: '',
license: 'ISC',
dependencies: {
'@line/bot-sdk': '^7.0.0',
express: '^4.17.1',
'node-tfidf': '0.0.2',
'tf-idf.js': '^0.3.2'
}
}
readJ_result.name
test-linebot
そして、test_.jsonの中身は以下のとおりで、以下に示すようにpackage.jsonと同一内容です。しかし、見た目が構造化されていないことが分かります。
{"name":"test-linebot","version":"1.0.0","description":"","main":"index.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"keywords":[],"author":"","license":"ISC","dependencies":{"@line/bot-sdk":"^7.0.0","express":"^4.17.1","node-tfidf":"0.0.2","tf-idf.js":"^0.3.2"}}
{
"name": "test-linebot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@line/bot-sdk": "^7.0.0",
"express": "^4.17.1",
"node-tfidf": "0.0.2",
"tf-idf.js": "^0.3.2"
}
}
そこで、参考のとおり、fs.writeFileSync(filePath, JSON.stringify(result, null, '\t'));
と改行コードを入れると以下のように成形されました。
※indentが少し広いですが、...
【参考】
⑧JSON.stringify()
{
"name": "test-linebot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@line/bot-sdk": "^7.0.0",
"express": "^4.17.1",
"node-tfidf": "0.0.2",
"tf-idf.js": "^0.3.2"
}
}
というわけで、fs.writeFileSync(filePath, JSON.stringify(result, null, ' '));
{
"name": "test-linebot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@line/bot-sdk": "^7.0.0",
"express": "^4.17.1",
"node-tfidf": "0.0.2",
"tf-idf.js": "^0.3.2"
}
}
fs.writeFileSync(filePath, JSON.stringify(result, null, ' '));
やっと答えにたどり着きました。
※ここは趣味の世界ですね
{
"name": "test-linebot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@line/bot-sdk": "^7.0.0",
"express": "^4.17.1",
"node-tfidf": "0.0.2",
"tf-idf.js": "^0.3.2"
}
}
まとめ
・ファイルとjsonファイルの書込み/読込を整理してみた
・jsonファイルの追記はやれそうだが、まだ適当な関数に昇華できていない
・ファイルを利用してbotを充実したいと思う