コンテンツにスキップ

fs

Since v8.0.75

fsモジュールは、JSHアプリケーション用にNode.js互換の同期ファイルシステムAPIを提供します。

API名と引数の形式はNode.jsのfsモジュールに従いますが、すべての関数は同期的に動作し、JSHの仮想ファイルシステム上で実行されます。Node.jsと動作が異なる点は、各関数の注意事項にまとめています。

パスとマウント

JSHは複数の種類のファイルシステムを1つの仮想ディレクトリツリーにマウントして提供します。fs関数に渡すパスはこの仮想パスで、相対パスは現在の作業ディレクトリを基準に解決されます。

マウントの種類によって、サポートされる機能が異なります。

マウントの種類例特徴
ホストディレクトリ/work, /tmpオペレーティングシステムのファイルシステムに直接接続されます。すべてのAPIをサポートします。
メモリベース/libファイルの内容をメモリに保持します。readFile/writeFileなどのパスベースのAPIはサポートしますが、書き込み用ファイルディスクリプター(open(path, 'w')など)はENOTSUPで失敗します。読み取り用ディスクリプターに対するfsync()もENOTSUPを返します。1ファイルの最大サイズは1GiBです。
読み取り専用(組み込み)/usr, /sbin実行ファイルに組み込まれたファイルです。書き込み操作はEACCESで失敗し、ディスクリプターに対するfsync()はENOTSUPを返します。
共有ファイルシステムサービス設定によるサービスコントローラーが複数のJSHプロセスに提供する共有ストレージです。1ファイルの最大サイズは1GiBです。
⚠️
異なるマウント間ではrename()でファイルを移動できず、EXDEVエラーが発生します。この場合はcopyFile()またはcp()でコピーしてから元のファイルを削除してください。

マウントの種類にかかわらず、各マウントのルートディレクトリ(例:/work、/lib)はマウントポイントです。ネストしたマウントによって生じる中間ディレクトリ(例:/a/bのみがマウントされている場合の/a)もマウントポイントとして扱います。マウントポイントはrmdir()、unlink()、rm()で削除できず、rename()の移動元・移動先にも指定できません。これらの操作はすべてEBUSYで失敗し、マウントポイントとマウント構成はそのまま維持されます。マウントポイントの中にあるファイルやディレクトリは通常どおり削除・移動できます。

エラー処理

ファイルシステム操作が失敗すると、Node.jsと同じ形式のErrorオブジェクトをスローします。

プロパティ説明
codeエラーコード文字列。例:ENOENT、EEXIST
errnoエラー番号(負の値)。例:-2
syscall失敗した操作の名前。例:open、mkdir、rmdir
path対象のパス。ファイルディスクリプターベースの関数(read()、write()、close()、fstat()、fsync()など)のエラーには含まれません。
destrename()のエラーにおける移動先のパス

エラーメッセージの形式はCODE: 説明, syscall 'path'です。例えばENOENT: no such file or directory, open '/work/none.txt'のようになります。

1
2
3
4
5
6
7
const fs = require('fs');
try {
    fs.readFile('/work/none.txt');
} catch (e) {
    console.println(e.code, e.errno, e.syscall, e.path);
    // ENOENT -2 open /work/none.txt
}
主なエラーコード
コードerrno意味
EPERM-1許可されていない操作
ENOENT-2ファイルまたはディレクトリが存在しない
EIO-5入出力エラー
EBADF-9無効なファイルディスクリプター。閉じられた、または存在しないディスクリプター、読み取り専用で開いたディスクリプターへの書き込みなど
EACCES-13権限がない。読み取り専用マウントへの書き込みを含む
EBUSY-16リソースが使用中。マウントポイントを削除・移動しようとしたときに発生
EEXIST-17すでに存在する
EXDEV-18異なるマウント間の移動
ENOTDIR-20ディレクトリではない
EISDIR-21ディレクトリに対して許可されていない操作
EINVAL-22無効な引数
EFBIG-27ファイルが大きすぎる。メモリベース・共有ファイルシステムの1GiB制限を超過
ENOSPC-28ストレージの空き容量不足
EROFS-30読み取り専用ファイルシステム
ENAMETOOLONG-36ファイル名が長すぎる
ENOTEMPTY-39ディレクトリが空ではない
ELOOP-40シンボリックリンクの段数が多すぎる
ENOTSUP-95サポートされていない操作
ECONFLICT-32009(JSH専用)共有ファイルシステムでディスクリプターを開いた後、別のプロセスが同じファイルを変更した
  • errnoの値は実行プラットフォームに関係なく、上の表の値(Linux基準)に固定されます。macOSやWindowsのNode.jsで報告されるerrnoの数値とは異なる場合があるため、エラーの判別にはerrnoではなくcodeを使用してください。
  • offset、length、position、lenなどの引数が範囲外の場合はRangeErrorをスローします。codeはERR_OUT_OF_RANGEで、errnoはありません。

readFile()

ファイルを読み取り、文字列(既定: utf8)またはバイト配列として返します。

構文
readFile(path[, options])
  • optionsはエンコーディング文字列または{ encoding }オブジェクトです。encoding: nullを指定するとバイト配列を返します。
  • ファイル全体をメモリに読み込みます。大きなファイルはcreateReadStream()またはopen()/read()で分割して読み取ってください。
使用例
1
2
3
const fs = require('fs');
const content = fs.readFile('/lib/fs.js', 'utf8');
console.println(content.length);

writeFile()

ファイルにデータを書き込みます。ファイルがなければ作成し、あれば上書きします。

構文
writeFile(path, data[, options])
  • 親ディレクトリが存在しない場合はENOENTで失敗します。必要に応じて先にmkdir(dir, { recursive: true })を呼び出してください。
  • メモリベースのマウントと共有ファイルシステムでは、1GiBを超えるファイルは書き込めません。
使用例
1
2
const fs = require('fs');
fs.writeFile('/work/test.txt', 'Hello', 'utf8');

appendFile()

ファイルの末尾にデータを追加します。ファイルがなければ新しく作成します。

構文
appendFile(path, data[, options])
使用例
1
2
3
const fs = require('fs');
fs.writeFile('/work/append.txt', 'Line 1\n', 'utf8');
fs.appendFile('/work/append.txt', 'Line 2\n', 'utf8');

countLines()

ファイルの行数(改行基準)を数えます。JSH専用の関数です。

構文
countLines(path)
使用例
1
2
const fs = require('fs');
console.println(fs.countLines('/work/append.txt'));

exists()

ファイルまたはディレクトリが存在するかどうかをtrue/falseで返します。

構文
exists(path)
  • シンボリックリンクはたどって確認します。リンク先が存在しないリンク(壊れたリンク)はfalseを返します。リンク自体の存在を確認するにはlstat()を使用してください。
  • 権限不足など、その他の理由で確認できない場合もfalseを返します。失敗の原因が必要な場合はaccess()またはstat()を使用してください。
使用例
1
2
3
const fs = require('fs');
console.println(fs.exists('/work/test.txt'));
console.println(fs.exists('/work/not-found.txt'));

stat()

ファイルまたはディレクトリのメタデータを返します。パスがシンボリックリンクの場合は、リンク先の情報を返します。

構文
stat(path)
返されるフィールド
  • name: ファイル名(パスの最後の要素)
  • size: バイト単位のサイズ
  • mode: ファイルモードオブジェクト。String(st.mode)はdrwxr-xr-xのような文字列を返します。
  • mtime, atime, ctime, birthtime: 現在の実装では、すべて更新時刻(mtime)と同じ値です。
  • isFile(), isDirectory(), isSymbolicLink()
  • isBlockDevice(), isCharacterDevice(), isFIFO(), isSocket()
使用例
1
2
3
4
const fs = require('fs');
const st = fs.stat('/work/test.txt');
console.println(st.isFile(), st.size);
console.println(st.name);

lstat()

ファイルのメタデータを返します。stat()と異なり、パスの最後の要素がシンボリックリンクの場合はリンクをたどらず、リンク自体の情報を返します。返されるフィールドはstat()と同じです。ネストしたマウントによって生じる中間ディレクトリは、stat()と同様にディレクトリとして返されます。

構文
lstat(path)
使用例
1
2
3
4
5
const fs = require('fs');
fs.writeFile('/work/target.txt', 'data');
fs.symlink('target.txt', '/work/link.txt');
console.println(fs.lstat('/work/link.txt').isSymbolicLink()); // true
console.println(fs.stat('/work/link.txt').isFile());          // true

readdir()

ディレクトリのエントリを読み取ります。

  • 既定: エントリ名のstring[]を返します。
  • withFileTypes: true: nameと型メソッド(isFile()、isDirectory()、isSymbolicLink()など)を持つエントリオブジェクトを返します。
  • recursive: true: サブディレクトリを含めて再帰的に返します。
構文
readdir(path[, options])
注意事項
  • 非再帰の読み取りでは、結果に.と..のエントリが含まれます。 Node.jsとは異なる動作のため、ディレクトリを走査する際は必ずこの2つのエントリをスキップしてください。スキップしないと、同じディレクトリを無限に再帰する可能性があります。
  • 再帰の読み取り(recursive: true)では.と..は含まれません。
    • 文字列の結果は、開始ディレクトリを基準とした相対パス(例: a/b/file.txt)です。
    • エントリオブジェクトのpathプロパティは、エントリが属するディレクトリの相対パスで、開始ディレクトリ直下のエントリでは''です。Node.jsのDirent.path(親ディレクトリのフルパス)とは異なります。
  • 再帰の読み取りでは、ディレクトリを指すシンボリックリンクの中には入りません。リンクはエントリとしてのみ返されます。
  • 再帰の読み取り中にサブディレクトリを読み取れない場合(権限不足など)、読み取り全体がエラーで失敗します。エラーオブジェクトのpathは失敗したサブディレクトリを指します。
使用例
1
2
3
4
const fs = require('fs');
const names = fs.readdir('/lib').filter(n => n !== '.' && n !== '..');
const all = fs.readdir('/work', { recursive: true });
console.println(names.length, all.length);

mkdir()

ディレクトリを作成します。

構文
mkdir(path[, options])
オプション
  • recursive: trueの場合、存在しない親ディレクトリも作成し、既存のディレクトリはエラーなしでスキップします。既定値はfalseです。
  • mode: 作成するディレクトリの権限です。既定値は0o755で、再帰作成時は新しく作成するすべてのディレクトリに適用されます。ホストディレクトリでは、オペレーティングシステムのumaskが追加で適用される場合があります。
動作
  • 非再帰の呼び出し(recursive: false)
    • 親ディレクトリが存在しない場合はENOENTで失敗します。親ディレクトリは自動的に作成されません。
    • 対象がすでに存在する場合は、ディレクトリでもファイルでもEEXISTで失敗します。
  • 再帰の呼び出し(recursive: true)
    • パスの途中に同じ名前のファイルがある場合はEEXISTで失敗します。Node.jsはこの場合ENOTDIRを返します。
    • 戻り値は常にundefinedです。Node.jsのように最初に作成されたパスは返しません。
使用例
1
2
3
const fs = require('fs');
fs.mkdir('/work/a/b/c', { recursive: true });
fs.mkdir('/work/private', { mode: 0o700 });

rmdir()

空のディレクトリを削除します。

構文
rmdir(path[, options])
  • ディレクトリが空でない場合はENOTEMPTY、対象がファイルの場合はENOTDIRで失敗します。
  • { recursive: true }を指定すると、先に子エントリをすべて削除します。Node.jsでは非推奨(deprecated)のオプションのため、新しいコードではrm(path, { recursive: true })の使用を推奨します。
  • 再帰削除の際、ディレクトリを指すシンボリックリンクはリンクのみを削除し、リンク先の内容は削除しません。
  • マウントポイントを指定するとEBUSYで失敗します。再帰削除でマウントポイントに遭遇したときの動作はrm()と同じです。

rm()

ファイル、シンボリックリンク、またはディレクトリを削除します。

構文
rm(path[, options])
オプション
  • recursive: trueの場合、ディレクトリとその内容をすべて削除します。
  • force: trueの場合、対象が存在しないとき(ENOENT)のエラーを無視します。
注意事項
  • 対象の種類はlstat()で判別します。シンボリックリンクは、リンク先がディレクトリであってもリンク自体のみが削除され、リンク先のディレクトリとその内容は保持されます。
  • recursiveなしでディレクトリを指定すると、空のディレクトリのみ削除されます。空でない場合はENOTEMPTYで失敗します。
  • force: trueはENOENTのみを無視します。権限不足(EACCES)、入出力エラー(EIO)などのその他のエラーはそのままスローします。マウントポイントで発生するEBUSYも無視しません。
  • 再帰削除の途中でエラーが発生すると、ただちに中断します。すでに削除されたエントリは復元されないため、一部のみが削除された状態で残る場合があります。
  • マウントポイントは例外的に扱います。対象自体またはその配下にあるマウントポイントは内容のみがすべて削除され、空のディレクトリとして残ります。残りのエントリの削除は続行し、すべてのエントリを処理した後、最初に遭遇したマウントポイントのパスでEBUSYをスローします。Linuxでマウントされたディレクトリをrm -rで削除した場合と同じ結果です。
使用例
1
2
const fs = require('fs');
fs.rm('/work/a', { recursive: true, force: true });

unlink()

ファイルまたはシンボリックリンクを削除します。

構文
unlink(path)
  • ディレクトリには使用できず、EISDIRで失敗します。ディレクトリにはrmdir()またはrm()を使用してください。
  • シンボリックリンクを指定すると、リンクのみが削除され、リンク先のファイルは保持されます。
  • マウントポイントを指定するとEBUSYで失敗します。
  • Windowsでは、読み取り専用属性のファイルも削除します。
📌
unlink()、rmdir()、rm()、rename()で最後のエントリを削除または移動しても、親ディレクトリはそのまま残ります。メモリベースのマウントと共有ファイルシステムも同様に動作します。

rename()

同じマウント内で、ファイルまたはディレクトリの名前を変更するか移動します。

構文
rename(oldPath, newPath)
  • 移動先のパスにファイルがある場合は、オペレーティングシステムのrenameの動作に従って上書きします。
  • 異なるマウント間の移動はEXDEVで失敗します。この場合、エラーオブジェクトのdestプロパティに移動先のパスが格納されます。
  • 移動元または移動先がマウントポイントの場合はEBUSYで失敗します。

copyFile()

単一のファイルをコピーします。

構文
copyFile(src, dest[, flags])
  • 既定では、コピー先のファイルが存在する場合は上書きします。
  • flagsにconstants.COPYFILE_EXCLを指定すると、コピー先のファイルが存在する場合にEEXISTで失敗します。
  • COPYFILE_FICLONE、COPYFILE_FICLONE_FORCEは無視され、通常のコピーを行います。
  • ファイルの内容のみをコピーします。コピー元ファイルの権限と更新時刻は保持されません。
  • ファイル全体をメモリに読み込んでから書き込むため、非常に大きなファイルのコピーには適していません。

cp()

ファイルまたはディレクトリをコピーします。

構文
cp(src, dest[, options])
オプション
  • recursive: ディレクトリをコピーするにはtrueである必要があります。省略すると、ディレクトリのコピーはEISDIRで失敗します。
  • force: trueの場合、コピー先にすでにあるファイルを上書きします。
注意事項
  • forceの既定値はfalseです。 コピー先のファイルがすでに存在する場合はEEXISTで失敗します。Node.jsのcpSync()は既定で上書きするため、動作が異なります。
  • コピー元のシンボリックリンクはたどって、リンク先の内容をコピーします。リンク自体はコピーしません。
  • ファイルの内容のみをコピーし、権限と更新時刻は保持されません。

symlink()

シンボリックリンクを作成します。

構文
symlink(target, path)
  • targetが相対パスの場合、Node.jsと同様にリンクが置かれるディレクトリを基準に解決され、相対パスの形のまま保存されます。
  • targetが/で始まる場合は、JSHの仮想パスとして扱われます。
  • リンク先がマウントされた領域の外を指すことになる場合(例: ../../../etc/passwd)はEACCESで失敗します。
  • Node.jsの第3引数(type)はサポートしていません。
使用例
1
2
3
4
5
const fs = require('fs');
fs.mkdir('/work/data', { recursive: true });
fs.writeFile('/work/data/v1.csv', 'a,b\n');
fs.symlink('v1.csv', '/work/data/current.csv');   // /work/data を基準に解決
console.println(fs.readFile('/work/data/current.csv'));

readlink()

シンボリックリンクのリンク先パスを読み取ります。

構文
readlink(path)
  • 戻り値は常に解決済みの絶対仮想パスです。 リンクが相対パス(v1.csv)で保存されていても、/work/data/v1.csvのように返されます。保存された文字列をそのまま返すNode.jsとは異なります。
  • シンボリックリンクではないパスにはEINVALをスローします。
  • リンクがマウントされた領域の外を指す場合はENOENTをスローします。

realpath()

すべてのシンボリックリンクと.、..を解決した実際のパスを返します。

構文
realpath(path)
  • パスの最後の要素だけでなく、途中のディレクトリのシンボリックリンクも解決します。
  • パスの要素が存在しない場合はENOENT、循環リンクなどでリンクを40回を超えてたどる必要がある場合はELOOPをスローします。
  • 戻り値はJSHの仮想パスです。

access()

パスが存在するかどうか、指定した権限でアクセスできるかどうかを確認します。アクセスできる場合はundefinedを返し、できない場合はエラーをスローします。

構文
access(path[, mode])
  • modeはconstants.F_OK(存在、既定値)、R_OK(読み取り)、W_OK(書き込み)、X_OK(実行)をビットORで組み合わせます。
  • パスが存在しない場合はENOENT、権限がない場合はEACCES、modeが0〜7の範囲外の場合はEINVALをスローします。
注意事項
  • ホストディレクトリのマウントでは、オペレーティングシステムの権限チェックを使用します。
  • Windowsでの動作はNode.jsと同じです。
    • 読み取り専用属性のファイルにW_OKをチェックするとEPERMをスローします。
    • X_OKは存在確認(F_OK)と同じように扱われます。
  • メモリベース・組み込み・共有ファイルシステムでは、JSHプロセスをファイルの所有者とみなし、ファイルモードの所有者の権限ビットで判断します。たとえば0o600のファイルはR_OK/W_OKの検査に成功し、0o004のファイルはR_OKの検査に失敗します。グループとACLは考慮しません。
  • 読み取り専用マウントでのW_OKチェックは常に失敗します。
  • access()で確認してからファイルを開く方法では、その間に状態が変わる可能性があります。可能であれば、ファイルを直接開いてエラーを処理してください。
使用例
1
2
3
4
5
6
7
const fs = require('fs');
try {
    fs.access('/work/test.txt', fs.constants.R_OK | fs.constants.W_OK);
    console.println('readable and writable');
} catch (e) {
    console.println('no access:', e.code);
}

truncate()

ファイルサイズを指定した長さに合わせます。

構文
truncate(path[, len])
  • lenを省略すると0に切り詰めます。
  • lenが現在のサイズより小さい場合は、先頭のlenバイトのみを残します。
  • lenが現在のサイズより大きい場合はファイルを拡張し、増えた部分は0バイトで埋めます。
  • lenが負の値または整数でない場合はRangeError(ERR_OUT_OF_RANGE)をスローします。
  • メモリベースのマウントと共有ファイルシステムで1GiBを超える長さを指定するとEFBIGで失敗し、ファイルは変更されません。

open()

ファイルを開き、数値のファイルディスクリプターを返します。

構文
open(path, flags[, mode])
  • flags: 文字列フラグ、またはconstants.O_*の値を組み合わせた数値フラグです。
  • mode: ファイルを新しく作成する際に使用する権限です。既定値は0o666です。
文字列フラグ
フラグ意味
r読み取り。ファイルがなければ失敗
r+読み書き。ファイルがなければ失敗
w書き込み。なければ作成し、あれば内容を空にする
w+読み書き。なければ作成し、あれば内容を空にする
a追記。なければ作成
a+読み取り/追記。なければ作成
wx, wx+, ax, ax+上と同じだが、ファイルがすでに存在する場合はEEXISTで失敗
注意事項
  • 上の表にない文字列フラグは、エラーなしでr(読み取り専用)として扱われます。タイプミスがあってもエラーにならず、その後のwrite()がEBADFで失敗する場合があるため、フラグ文字列は正確に指定してください。
  • メモリベースのマウント(例: /lib)では、読み取り用のディスクリプターのみ開けます。書き込みフラグを指定するとENOTSUPで失敗するため、writeFile()/appendFile()を使用してください。
  • 読み取り専用(組み込み)マウントで書き込みフラグを指定して開くとEACCESで失敗します。
  • 使用したディスクリプターは必ずclose()で閉じてください。

close()

ファイルディスクリプターを閉じます。

構文
close(fd)
  • すでに閉じられた、または存在しないディスクリプターはEBADFで失敗します。
  • 共有ファイルシステムでは、閉じた時点で変更内容が保存されます。ディスクリプターを開いた後に別のプロセスが同じファイルを変更していた場合はECONFLICTで失敗します。

read()

ファイルディスクリプターからデータを読み取ってバッファに格納し、読み取ったバイト数を返します。ファイルの末尾では0を返します。

構文
read(fd, buffer, offset, length[, position])
  • buffer: データを受け取るUint8Array、Buffer、または数値配列
  • offset: バッファ内で書き込みを開始する位置。既定値は0です。
  • length: 読み取る最大バイト数。既定値はbuffer.length - offsetです。
  • position: ファイル内で読み取りを開始する位置
    • nullまたは省略: 現在のファイル位置から読み取り、読み取った分だけ現在位置が進みます。
    • 0以上の整数: 指定した位置から読み取り、現在のファイル位置は変わりません。
注意事項
  • offset、length、positionが範囲外の場合はRangeError(ERR_OUT_OF_RANGE)をスローします。例えば、offset + lengthがバッファサイズを超える場合や、positionが負の値の場合です。
  • 書き込み専用で開いたディスクリプターを読み取るとEBADFで失敗します。
  • Linux/macOSでディレクトリのディスクリプターを読み取るとEISDIRで失敗します。ディレクトリの内容はreaddir()で読み取ってください。
使用例
1
2
3
4
5
6
7
const fs = require('fs');
fs.writeFile('/work/data.bin', 'ABCDEFGH');
const fd = fs.open('/work/data.bin', 'r');
const buf = new Uint8Array(4);
fs.read(fd, buf, 0, 4, 4);   // "EFGH" を読み取り、ファイル位置は変わらない
fs.read(fd, buf, 0, 4);      // 現在位置から "ABCD" を読み取る
fs.close(fd);

write()

バッファまたは文字列のデータをファイルディスクリプターに書き込み、書き込んだバイト数を返します。

構文
write(fd, data[, offset[, length[, position]]])
  • data: Uint8Array、Buffer、数値配列、または文字列。文字列はUTF-8バイトに変換して書き込みます。
  • offset: data内で書き込みを開始するバイト位置。既定値は0です。
  • length: 書き込むバイト数。既定値はoffsetから末尾までです。0を指定すると何も書き込みません。
  • position: ファイル内で書き込みを開始する位置
    • nullまたは省略: 現在のファイル位置に書き込み、書き込んだ分だけ現在位置が進みます。
    • 0以上の整数: 指定した位置に書き込み、現在のファイル位置は変わりません。 位置がファイルの末尾より後ろの場合、その間は0バイトで埋められます。
注意事項
  • 文字列を書き込む場合も、引数の順序は(fd, data, offset, length, position)です。 Node.jsのwriteSync(fd, string, position, encoding)の形式はサポートしていません。例えばwrite(fd, 'Z', 3)の3はファイル位置ではなくoffsetとして解釈されるため、ERR_OUT_OF_RANGEが発生します。
  • 文字列のoffsetとlengthは、文字数ではなくUTF-8のバイト単位です。
  • a、a+などの追記モードで開いたディスクリプターは、positionを指定しても無視し、常にファイルの末尾に書き込みます。
  • offset、length、positionが範囲外の場合はRangeError(ERR_OUT_OF_RANGE)をスローします。
  • 読み取り専用で開いたディスクリプターに書き込むとEBADFで失敗します。
  • 共有ファイルシステムで、書き込みの結果が1GiBを超える場合はEFBIGで失敗します。
使用例
1
2
3
4
5
6
7
const fs = require('fs');
const fd = fs.open('/work/out.txt', 'w+');
fs.write(fd, 'Hello World');                // 現在位置に書き込む
fs.write(fd, 'J', 0, 1, 0);                 // 先頭1バイトを上書き: "Jello World"
const bytes = new Uint8Array([0x21, 0x21]);
fs.write(fd, bytes, 0, bytes.length);       // 現在位置に "!!" を追加
fs.close(fd);

fstat()

ファイルディスクリプターのメタデータを返します。

構文
fstat(fd)
  • 返されるオブジェクトはname、size、mode、mtimeと型メソッド(isFile()など)を提供します。atime、ctime、birthtimeは含まれません。

fchmod(), fchown()

ファイルディスクリプター基準でモード/所有者を変更します。

構文
fchmod(fd, mode)
fchown(fd, uid, gid)
  • Windowsのホストディレクトリマウントで開いたファイルディスクリプターでは、何もせずに成功します。
  • その他のマウントでは、それぞれのファイルシステムの動作に従います。たとえば、読み取り専用(組み込み)マウントのディスクリプターではEACCESをスローします。

fsync(), fdatasync()

保留中のファイルデータをストレージに同期します。

構文
fsync(fd)
fdatasync(fd)
  • 現在、fdatasync()はfsync()と同じように動作します。
  • 読み取り専用(組み込み)マウントで開いたディスクリプターと、メモリベースのマウント(例:/lib)の読み取り用ディスクリプターには同期する対象がないため、ENOTSUPをスローします。Node.jsとは異なる動作です。
  • 共有ファイルシステムで、ディスクリプターを開いた後に別のプロセスが同じファイルを変更していた場合はECONFLICTで失敗します。

chmod(), chown()

パス基準でモード/所有者を変更します。

Windowsのホストディレクトリマウントでは、chmod/chownは何もしない互換動作です。メモリベース、組み込み、共有ファイルシステムでは、それぞれの動作に従います。

構文
chmod(path, mode)
chown(path, uid, gid)

createReadStream(), createWriteStream()

EventEmitterベースの使用方法と互換性のあるストリームオブジェクトを作成します。

構文
createReadStream(path[, options])
createWriteStream(path[, options])
使用例
1
2
3
4
const fs = require('fs');
const rs = fs.createReadStream('/work/in.txt', { encoding: 'utf8' });
const ws = fs.createWriteStream('/work/out.txt', { encoding: 'utf8' });
rs.pipe(ws);

platform(), arch()

ランタイムのプラットフォームとアーキテクチャの文字列を返します。

構文
platform()
arch()
使用例
1
2
3
const fs = require('fs');
console.println(fs.platform());
console.println(fs.arch());

constants

アクセス、コピー、ファイルオープンのフラグを含む定数オブジェクトです。

主なフィールド
  • アクセス: F_OK(0), R_OK(4), W_OK(2), X_OK(1)
  • コピー: COPYFILE_EXCL, COPYFILE_FICLONE, COPYFILE_FICLONE_FORCE
  • ファイルオープン: O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_TRUNC, O_APPEND

ファイルオープン定数の実際の値は実行プラットフォームによって異なる場合があるため、数値を直接記述せずに定数を使用してください。

使用例
1
2
3
4
const fs = require('fs');
fs.access('/work/test.txt', fs.constants.F_OK);
const fd = fs.open('/work/new.txt', fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL);
fs.close(fd);

別名

読みやすさのため、このドキュメントではSyncのない名前でAPIを紹介します。

Node.jsとの互換性のため、Sync接尾辞を持つ別名も提供します。2つの名前は同じ関数で、どちらも同期的に動作します。コールバックやPromiseベースのAPIは提供しません。

例: readFileSync, writeFileSync, appendFileSync, readdirSync, mkdirSync, rmSync, statSync, openSync, closeSync, readSync, writeSync, fstatSync, fsyncSync, fdatasyncSync.

使用例

例1:JSONファイルの読み取りと解析

1
2
3
4
5
6
7
8
9
const fs = require('fs');

try {
    const content = fs.readFile('/path/to/config.json', 'utf8');
    const config = JSON.parse(content);
    console.println('Config loaded:', config);
} catch (e) {
    console.println('Error reading config:', e.code || e);
}

例2:ログファイルの書き込み

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const fs = require('fs');

function log(message) {
    const timestamp = new Date().toISOString();
    const logEntry = `[${timestamp}] ${message}\n`;
    fs.appendFile('/tmp/app.log', logEntry, 'utf8');
}

log('Application started');
log('Processing request');

例3:ディレクトリツリーの走査

非再帰のreaddir()の結果には.と..が含まれるため、必ずスキップしてください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const fs = require('fs');

function walkDir(dir, callback, indent = '') {
    const entries = fs.readdir(dir, { withFileTypes: true });

    entries.forEach(entry => {
        if (entry.name === '.' || entry.name === '..') {
            return;
        }
        const fullPath = dir + '/' + entry.name;

        if (entry.isDirectory()) {
            console.println(indent + '[DIR] ' + entry.name);
            walkDir(fullPath, callback, indent + '  ');
        } else {
            console.println(indent + entry.name);
            callback(fullPath);
        }
    });
}

walkDir('/tmp', (file) => {
    // 各ファイルを処理
});

すべてのパスだけが必要な場合は、recursiveオプションを使用できます。

1
2
const fs = require('fs');
fs.readdir('/tmp', { recursive: true }).forEach(p => console.println(p));

例4:ファイルのバックアップ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const fs = require('fs');

function backupFile(path) {
    if (!fs.exists(path)) {
        throw new Error('File does not exist');
    }

    const timestamp = Date.now();
    const backupPath = path + '.backup.' + timestamp;

    fs.copyFile(path, backupPath, fs.constants.COPYFILE_EXCL);
    console.println('Backup created:', backupPath);

    return backupPath;
}

backupFile('/tmp/important.txt');

例5:安全なファイル書き込み

先に一時ファイルに書き込み、rename()で置き換えます。rename()は同じマウント内でのみ動作するため、一時ファイルは対象ファイルと同じディレクトリに作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
const fs = require('fs');

function safeWriteFile(path, data) {
    const tempPath = path + '.tmp';

    try {
        // 先に一時ファイルに書き込み
        fs.writeFile(tempPath, data, 'utf8');

        // 成功した場合は対象の名前に変更
        fs.rename(tempPath, path);

        console.println('File written safely');
    } catch (e) {
        // 一時ファイルがあれば削除
        fs.rm(tempPath, { force: true });
        throw e;
    }
}

safeWriteFile('/tmp/data.txt', 'Important data');

例6:エラーコードに応じた処理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const fs = require('fs');

function ensureDir(path) {
    try {
        fs.mkdir(path);
    } catch (e) {
        if (e.code === 'EEXIST' && fs.stat(path).isDirectory()) {
            return;   // すでに存在する
        }
        if (e.code === 'ENOENT') {
            fs.mkdir(path, { recursive: true });   // 親ディレクトリがない
            return;
        }
        throw e;
    }
}

ensureDir('/work/output/2024');
最終更新日