'node:os'
モジュールを使用した標準ディレクトリのパス取得path.normalize()
:パスの正規化path.resolve()
(引数1つ):パスの正規化と完全修飾化path.relative()
:相対パスの作成path.format()
:部分からパスを作成するfile:
URLの使用URL
クラスfile:
URLこの章では、Node.jsにおけるファイルシステムパスとファイルURLの使用方法を学びます。
この章では、Node.jsにおけるパス関連の機能を探ります。
'node:path'
モジュールにあります。process
には、*カレントワーキングディレクトリ*を変更するためのメソッドがあります(その意味についてはすぐに説明します)。'node:os'
モジュールには、重要なディレクトリのパスを返す関数が含まれています。'node:path'
APIへのアクセス方法3種類'node:path'
モジュールは、多くの場合、次のようにインポートされます。
import * as path from 'node:path';
この章では、このインポート文は時々省略されます。また、次のインポートも省略します。
import * as assert from 'node:assert/strict';
NodeのパスAPIには3つの方法でアクセスできます。
プラットフォーム固有のバージョンのAPIにアクセスできます。
path.posix
はmacOSを含むUnix系システムをサポートします。path.win32
はWindowsをサポートします。path
自体は常に現在のプラットフォームをサポートします。たとえば、これはmacOSでのREPLの対話です。
> path.parse === path.posix.parsetrue
ファイルシステムパスを解析する関数path.parse()
が、2つのプラットフォームでどのように異なるかを見てみましょう。
> path.win32.parse(String.raw`C:\Users\jane\file.txt`){
dir: 'C:\\Users\\jane',
root: 'C:\\',
base: 'file.txt',
name: 'file',
ext: '.txt',
}
> path.posix.parse(String.raw`C:\Users\jane\file.txt`){
dir: '',
root: '',
base: 'C:\\Users\\jane\\file.txt',
name: 'C:\\Users\\jane\\file',
ext: '.txt',
}
Windowsのパスを解析します。最初にpath.win32
APIを使用して正しく解析し、次にpath.posix
APIを使用して解析します。後者の場合、パスが正しく分割されていないことがわかります。たとえば、ファイルの基本名はfile.txt
である必要があります(他のプロパティの意味については後で詳しく説明します)。
用語
空でないパスは、1つ以上の*パスセグメント*で構成されます。ほとんどの場合、ディレクトリまたはファイルの名前です。
パス内の2つの隣接するパスセグメントを区切るために*パスセパレータ*が使用されます。path.sep
には、現在のプラットフォームのパスセパレータが含まれています。
.equal(
assert.posix.sep, '/' // Path separator on Unix
path;
).equal(
assert.win32.sep, '\\' // Path separator on Windows
path; )
パスリスト内の要素を区切るために*パスデリミタ*が使用されます。path.delimiter
には、現在のプラットフォームのパスデリミタが含まれています。
.equal(
assert.posix.delimiter, ':' // Path delimiter on Unix
path;
).equal(
assert.win32.delimiter, ';' // Path delimiter on Windows
path; )
PATHシェル変数を調べると、パスセパレータとパスデリミタを確認できます。PATHシェル変数には、シェルでコマンドが入力されたときに、オペレーティングシステムが実行可能ファイルを探すパスが含まれています。
これはmacOSのPATH(シェル変数$PATH
)の例です。
> process.env.PATH.split(/(?<=:)/)
['/opt/homebrew/bin:',
'/opt/homebrew/sbin:',
'/usr/local/bin:',
'/usr/bin:',
'/bin:',
'/usr/sbin:',
'/sbin',
]
後方参照アサーション(?<=:)
は、指定された位置の前にコロンがある場合に一致しますが、何もキャプチャしません。そのため、パスデリミタ':'
は前のパスに含まれています。後方参照アサーションについてはこちら
これはWindowsのPATH(シェル変数%Path%
)の例です。
> process.env.Path.split(/(?<=;)/)
['C:\\Windows\\system32;',
'C:\\Windows;',
'C:\\Windows\\System32\\Wbem;',
'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;',
'C:\\Windows\\System32\\OpenSSH\\;',
'C:\\ProgramData\\chocolatey\\bin;',
'C:\\Program Files\\nodejs\\',
]
多くのシェルには、*カレントワーキングディレクトリ*(CWD)という概念があります。「現在いるディレクトリ」です。
cd
です。process
はグローバルなNode.js変数です。CWDを取得および設定するためのメソッドを提供します。
process.cwd()
はCWDを返します。process.chdir(dirPath)
はCWDをdirPath
に変更します。dirPath
にはディレクトリが存在する必要があります。Node.jsは、パスが*完全修飾パス*(完全なパス)でない場合、CWDを使用して不足している部分を補います。これにより、様々な関数(例:fs.readFileSync()
)で部分修飾パスを使用できます。
次のコードは、Unixでのprocess.chdir()
とprocess.cwd()
を示しています。
process.chdir('/home/jane');
.equal(
assertprocess.cwd(), '/home/jane'
; )
これまで、Unixでのカレントワーキングディレクトリを使用してきました。Windowsは異なります。
path.chdir()
を使用して、同時に両方設定できます。
process.chdir('C:\\Windows');
process.chdir('Z:\\tmp');
ドライブを再び参照すると、Node.jsはそのドライブの以前のカレントディレクトリを記憶しています。
.equal(
assertprocess.cwd(), 'Z:\\tmp'
;
)process.chdir('C:');
.equal(
assertprocess.cwd(), 'C:\\Windows'
; )
Unixは2種類のパスのみ認識します。
*絶対パス*は完全修飾パスであり、スラッシュで始まります。
/home/john/proj
*相対パス*は部分修飾パスであり、ファイル名またはドットで始まります。
. (current directory)
.. (parent directory)
dir
./dir
../dir
../../dir/subdir
path.resolve()
(後述)を使用して、相対パスを絶対パスに対して解決してみましょう。結果は絶対パスになります。
> const abs = '/home/john/proj';
> path.resolve(abs, '.')'/home/john/proj'
> path.resolve(abs, '..')'/home/john'
> path.resolve(abs, 'dir')'/home/john/proj/dir'
> path.resolve(abs, './dir')'/home/john/proj/dir'
> path.resolve(abs, '../dir')'/home/john/dir'
> path.resolve(abs, '../../dir/subdir')'/home/dir/subdir'
Windowsは4種類のパスを区別します(詳細については、Microsoftのドキュメントを参照してください)。
ドライブ文字を含む絶対パスは完全修飾パスです。その他のパスはすべて部分修飾パスです。
ドライブ文字のない**絶対パスの解決**は、完全修飾パスfull
に対して行われ、full
のドライブ文字が取得されます。
> const full = 'C:\\Users\\jane\\proj';
> path.resolve(full, '\\Windows')'C:\\Windows'
ドライブ文字のない**相対パスの解決**は、完全修飾パスに対して行われ、後者を更新したものと見なすことができます。
> const full = 'C:\\Users\\jane\\proj';
> path.resolve(full, '.')'C:\\Users\\jane\\proj'
> path.resolve(full, '..')'C:\\Users\\jane'
> path.resolve(full, 'dir')'C:\\Users\\jane\\proj\\dir'
> path.resolve(full, '.\\dir')'C:\\Users\\jane\\proj\\dir'
> path.resolve(full, '..\\dir')'C:\\Users\\jane\\dir'
> path.resolve(full, '..\\..\\dir')'C:\\Users\\dir'
ドライブ文字を含む**相対パスrel
の解決**は、完全修飾パスfull
に対して行われ、rel
のドライブ文字に依存します。
full
と同じドライブ文字?full
に対してrel
を解決します。full
とは異なるドライブ文字?rel
のドライブのカレントディレクトリに対してrel
を解決します。次のようになります。
// Configure current directories for C: and Z:
process.chdir('C:\\Windows\\System');
process.chdir('Z:\\tmp');
const full = 'C:\\Users\\jane\\proj';
// Same drive letter
.equal(
assert.resolve(full, 'C:dir'),
path'C:\\Users\\jane\\proj\\dir'
;
).equal(
assert.resolve(full, 'C:'),
path'C:\\Users\\jane\\proj'
;
)
// Different drive letter
.equal(
assert.resolve(full, 'Z:dir'),
path'Z:\\tmp\\dir'
;
).equal(
assert.resolve(full, 'Z:'),
path'Z:\\tmp'
; )
'node:os'
モジュールを使用した標準ディレクトリのパス取得'node:os'
モジュールは、2つの重要なディレクトリのパスを提供します。
os.homedir()
は、現在のユーザーのホームディレクトリのパスを返します。例:
> os.homedir() // macOS'/Users/rauschma'
> os.homedir() // Windows'C:\\Users\\axel'
os.tmpdir()
は、オペレーティングシステムの一時ファイル用ディレクトリのパスを返します。例:
> os.tmpdir() // macOS'/var/folders/ph/sz0384m11vxf5byk12fzjms40000gn/T'
> os.tmpdir() // Windows'C:\\Users\\axel\\AppData\\Local\\Temp'
パスを連結するための関数は2つあります。
path.resolve()
は常に完全修飾パスを返します。path.join()
は相対パスを保持します。path.resolve()
:完全修飾パスを作成するためのパスの連結.resolve(...paths: Array<string>): string path
paths
を連結して完全修飾パスを返します。次のアルゴリズムを使用します。
path[0]
を解決します。path[1]
を解決します。引数なしの場合、path.resolve()
はカレントワーキングディレクトリのパスを返します。
> process.cwd()'/usr/local'
> path.resolve()'/usr/local'
1つ以上の相対パスが、カレントワーキングディレクトリから始めて解決に使用されます。
> path.resolve('.')'/usr/local'
> path.resolve('..')'/usr'
> path.resolve('bin')'/usr/local/bin'
> path.resolve('./bin', 'sub')'/usr/local/bin/sub'
> path.resolve('../lib', 'log')'/usr/lib/log'
完全修飾パスは、前の結果を置き換えます。
> path.resolve('bin', '/home')'/home'
これにより、部分修飾パスを完全修飾パスに対して解決できます。
> path.resolve('/home/john', 'proj', 'src')'/home/john/proj/src'
path.join()
:相対パスを保持したままパスの連結を行う.join(...paths: Array<string>): string path
paths[0]
から開始し、残りのパスを昇順または降順の指示として解釈します。path.resolve()
とは異なり、この関数は部分修飾パスを保持します。paths[0]
が部分修飾パスであれば、結果は部分修飾パスになります。完全修飾パスであれば、結果は完全修飾パスになります。
降順の例
> path.posix.join('/usr/local', 'sub', 'subsub')'/usr/local/sub/subsub'
> path.posix.join('relative/dir', 'sub', 'subsub')'relative/dir/sub/subsub'
ダブルドットは昇順になります。
> path.posix.join('/usr/local', '..')'/usr'
> path.posix.join('relative/dir', '..')'relative'
単一のドットは何も行いません。
> path.posix.join('/usr/local', '.')'/usr/local'
> path.posix.join('relative/dir', '.')'relative/dir'
最初の引数以降の引数が完全修飾パスである場合、相対パスとして解釈されます。
> path.posix.join('dir', '/tmp')'dir/tmp'
> path.win32.join('dir', 'C:\\Users')'dir\\C:\\Users'
3つ以上の引数を使用する場合
> path.posix.join('/usr/local', '../lib', '.', 'log')'/usr/lib/log'
path.normalize()
:パスの正規化を確保する.normalize(path: string): string path
Unixでは、path.normalize()
は
.
)であるパスセグメントを削除します。..
)であるパスセグメントを解決します。例:
// Fully qualified path
.equal(
assert.posix.normalize('/home/./john/lib/../photos///pet'),
path'/home/john/photos/pet'
;
)
// Partially qualified path
.equal(
assert.posix.normalize('./john/lib/../photos///pet'),
path'john/photos/pet'
; )
Windowsでは、path.normalize()
は
.
)であるパスセグメントを削除します。..
)であるパスセグメントを解決します。/
)(有効です)を推奨されるパス区切り文字(\
)に変換します。例:
// Fully qualified path
.equal(
assert.win32.normalize('C:\\Users/jane\\doc\\..\\proj\\\\src'),
path'C:\\Users\\jane\\proj\\src'
;
)
// Partially qualified path
.equal(
assert.win32.normalize('.\\jane\\doc\\..\\proj\\\\src'),
path'jane\\proj\\src'
; )
path.join()
に単一の引数を指定した場合も正規化され、path.normalize()
と同じように動作することに注意してください。
> path.posix.normalize('/home/./john/lib/../photos///pet')'/home/john/photos/pet'
> path.posix.join('/home/./john/lib/../photos///pet')'/home/john/photos/pet'
> path.posix.normalize('./john/lib/../photos///pet')'john/photos/pet'
> path.posix.join('./john/lib/../photos///pet')'john/photos/pet'
path.resolve()
(1つの引数):パスの正規化と完全修飾を確保する既にpath.resolve()
について説明しました。単一の引数で呼び出されると、パスを正規化し、完全修飾されていることを確認します。
Unixでpath.resolve()
を使用する
> process.cwd()'/usr/local'
> path.resolve('/home/./john/lib/../photos///pet')'/home/john/photos/pet'
> path.resolve('./john/lib/../photos///pet')'/usr/local/john/photos/pet'
Windowsでpath.resolve()
を使用する
> process.cwd()'C:\\Windows\\System'
> path.resolve('C:\\Users/jane\\doc\\..\\proj\\\\src')'C:\\Users\\jane\\proj\\src'
> path.resolve('.\\jane\\doc\\..\\proj\\\\src')'C:\\Windows\\System\\jane\\proj\\src'
path.relative()
:相対パスの作成.relative(sourcePath: string, destinationPath: string): string path
sourcePath
からdestinationPath
への相対パスを返します。
> path.posix.relative('/home/john/', '/home/john/proj/my-lib/README.md')'proj/my-lib/README.md'
> path.posix.relative('/tmp/proj/my-lib/', '/tmp/doc/zsh.txt')'../../doc/zsh.txt'
Windowsでは、sourcePath
とdestinationPath
が異なるドライブにある場合、完全修飾パスが取得されます。
> path.win32.relative('Z:\\tmp\\', 'C:\\Users\\Jane\\')'C:\\Users\\Jane'
この関数は相対パスでも機能します。
> path.posix.relative('proj/my-lib/', 'doc/zsh.txt')'../../doc/zsh.txt'
path.parse()
:パス部分をオブジェクトで作成するtype PathObject = {
: string,
dir: string,
root: string,
base: string,
name: string,
ext;
}.parse(path: string): PathObject path
path
の様々な部分を抽出し、以下のプロパティを持つオブジェクトで返します。
.base
:パスの最後のセグメント.ext
:baseのファイル名拡張子.name
:拡張子を除いたbase。この部分はパスの *ステム* とも呼ばれます。.root
:パスの開始部分(最初のセグメントの前).dir
:baseが存在するディレクトリ - baseを除いたパス後で、path.parse()
の逆関数であるpath.format()
関数について説明します。これは、パス部分を持つオブジェクトをパスに変換します。
path.parse()
Unixでpath.parse()
を使用すると、次のようになります。
> path.posix.parse('/home/jane/file.txt'){
dir: '/home/jane',
root: '/',
base: 'file.txt',
name: 'file',
ext: '.txt',
}
次の図は、各部分の範囲を視覚的に表したものです。
/ home/jane / file .txt
| root | | name | ext |
| dir | base |
例えば、.dir
はbaseを除いたパスであり、.base
は.name
と.ext
の組み合わせであることがわかります。
path.parse()
Windowsでのpath.parse()
の動作は次のとおりです。
> path.win32.parse(String.raw`C:\Users\john\file.txt`){
dir: 'C:\\Users\\john',
root: 'C:\\',
base: 'file.txt',
name: 'file',
ext: '.txt',
}
これは結果の図です。
C:\ Users\john \ file .txt
| root | | name | ext |
| dir | base |
path.basename()
:パスのbaseを抽出する.basename(path, ext?) path
path
のbaseを返します。
> path.basename('/home/jane/file.txt')'file.txt'
オプションで、この関数はサフィックスも削除できます。
> path.basename('/home/jane/file.txt', '.txt')'file'
> path.basename('/home/jane/file.txt', 'txt')'file.'
> path.basename('/home/jane/file.txt', 'xt')'file.t'
拡張子の削除は大文字と小文字が区別されます - Windowsでも!
> path.win32.basename(String.raw`C:\Users\john\file.txt`, '.txt')'file'
> path.win32.basename(String.raw`C:\Users\john\file.txt`, '.TXT')'file.txt'
path.dirname()
:パスの親ディレクトリを抽出する.dirname(path) path
path
にあるファイルまたはディレクトリの親ディレクトリを返します。
> path.win32.dirname(String.raw`C:\Users\john\file.txt`)'C:\\Users\\john'
> path.win32.dirname('C:\\Users\\john\\dir\\')'C:\\Users\\john'
> path.posix.dirname('/home/jane/file.txt')'/home/jane'
> path.posix.dirname('/home/jane/dir/')'/home/jane'
path.extname()
:パスの拡張子を抽出する.extname(path) path
path
の拡張子を返します。
> path.extname('/home/jane/file.txt')'.txt'
> path.extname('/home/jane/file.')'.'
> path.extname('/home/jane/file')''
> path.extname('/home/jane/')''
> path.extname('/home/jane')''
path.isAbsolute()
:指定されたパスは絶対パスか?.isAbsolute(path: string): boolean path
path
が絶対パスの場合はtrue
、それ以外の場合はfalse
を返します。
Unixでの結果は簡単です。
> path.posix.isAbsolute('/home/john')true
> path.posix.isAbsolute('john')false
Windowsでは、「絶対」は必ずしも「完全修飾」を意味しません(最初のパスのみが完全修飾されます)。
> path.win32.isAbsolute('C:\\Users\\jane')true
> path.win32.isAbsolute('\\Users\\jane')true
> path.win32.isAbsolute('C:jane')false
> path.win32.isAbsolute('jane')false
path.format()
:部分からパスを作成するtype PathObject = {
: string,
dir: string,
root: string,
base: string,
name: string,
ext;
}.format(pathObject: PathObject): string path
パスオブジェクトからパスを作成します。
> path.format({dir: '/home/jane', base: 'file.txt'})'/home/jane/file.txt'
path.format()
を使用して、パスの拡張子を変更できます。
function changeFilenameExtension(pathStr, newExtension) {
if (!newExtension.startsWith('.')) {
throw new Error(
'Extension must start with a dot: '
+ JSON.stringify(newExtension)
;
)
}const parts = path.parse(pathStr);
return path.format({
...parts,
base: undefined, // prevent .base from overriding .name and .ext
ext: newExtension,
;
})
}
.equal(
assertchangeFilenameExtension('/tmp/file.md', '.html'),
'/tmp/file.html'
;
).equal(
assertchangeFilenameExtension('/tmp/file', '.html'),
'/tmp/file.html'
;
).equal(
assertchangeFilenameExtension('/tmp/file/', '.html'),
'/tmp/file.html'
; )
元のファイル名拡張子がわかっている場合は、正規表現を使用してファイル名拡張子を変更することもできます。
> '/tmp/file.md'.replace(/\.md$/i, '.html')'/tmp/file.html'
> '/tmp/file.MD'.replace(/\.md$/i, '.html')'/tmp/file.html'
異なるプラットフォームで同じパスを使用したい場合があります。その場合、2つの問題があります。
例として、データを含むディレクトリで動作するNode.jsアプリを考えてみましょう。アプリは2種類のパスで構成できると仮定します。
前述の問題のため
プラットフォーム間で完全修飾パスを再利用できません。
データディレクトリを指すパスを再利用できます。このようなパスは、構成ファイル(データディレクトリ内にある場合とない場合があります)やアプリのコード内の定数に保存できます。そのためには
次のセクションでは、両方をどのように実現できるかを説明します。
プラットフォームに依存しない相対パスは、パスセグメントの配列として保存し、次のようにプラットフォーム固有の完全修飾パスに変換できます。
const universalRelativePath = ['static', 'img', 'logo.jpg'];
const dataDirUnix = '/home/john/data-dir';
.equal(
assert.posix.resolve(dataDirUnix, ...universalRelativePath),
path'/home/john/data-dir/static/img/logo.jpg'
;
)
const dataDirWindows = 'C:\\Users\\jane\\data-dir';
.equal(
assert.win32.resolve(dataDirWindows, ...universalRelativePath),
path'C:\\Users\\jane\\data-dir\\static\\img\\logo.jpg'
; )
プラットフォーム固有の相対パスを作成するには、以下を使用できます。
const dataDir = '/home/john/data-dir';
const pathInDataDir = '/home/john/data-dir/static/img/logo.jpg';
.equal(
assert.relative(dataDir, pathInDataDir),
path'static/img/logo.jpg'
; )
次の関数は、プラットフォーム固有の相対パスをプラットフォームに依存しないパスに変換します。
import * as path from 'node:path';
function splitRelativePathIntoSegments(relPath) {
if (path.isAbsolute(relPath)) {
throw new Error('Path isn’t relative: ' + relPath);
}= path.normalize(relPath);
relPath const result = [];
while (true) {
const base = path.basename(relPath);
if (base.length === 0) break;
.unshift(base);
resultconst dir = path.dirname(relPath);
if (dir === '.') break;
= dir;
relPath
}return result;
}
UnixでsplitRelativePathIntoSegments()
を使用する
> splitRelativePathIntoSegments('static/img/logo.jpg')[ 'static', 'img', 'logo.jpg' ]
> splitRelativePathIntoSegments('file.txt')[ 'file.txt' ]
WindowsでsplitRelativePathIntoSegments()
を使用する
> splitRelativePathIntoSegments('static/img/logo.jpg')[ 'static', 'img', 'logo.jpg' ]
> splitRelativePathIntoSegments('C:static/img/logo.jpg')[ 'static', 'img', 'logo.jpg' ]
> splitRelativePathIntoSegments('file.txt')[ 'file.txt' ]
> splitRelativePathIntoSegments('C:file.txt')[ 'file.txt' ]
npmモジュール'minimatch'
を使用すると、*glob式*、*globパターン*、または*glob*と呼ばれるパターンに対してパスを照合できます。
import minimatch from 'minimatch';
.equal(
assertminimatch('/dir/sub/file.txt', '/dir/sub/*.txt'), true
;
).equal(
assertminimatch('/dir/sub/file.txt', '/**/file.txt'), true
; )
globの使用例
その他のglobライブラリ
minimatchのAPI全体は、プロジェクトのREADMEファイルに記載されています。このセクションでは、最も重要な機能を見ていきます。
MinimatchはglobをJavaScriptのRegExp
オブジェクトにコンパイルし、それを使用して照合します。
minimatch()
:一度コンパイルして照合するminimatch(path: string, glob: string, options?: MinimatchOptions): boolean
glob
がpath
と一致する場合はtrue
、それ以外の場合はfalse
を返します。
2つの興味深いオプション
.dot: boolean
(デフォルト:false
)true
の場合、*
や**
などのワイルドカード記号は、「非表示」のパスセグメント(名前がドットで始まるセグメント)と一致します。
> minimatch('/usr/local/.tmp/data.json', '/usr/**/data.json')false
> minimatch('/usr/local/.tmp/data.json', '/usr/**/data.json', {dot: true})true
> minimatch('/tmp/.log/events.txt', '/tmp/*/events.txt')false
> minimatch('/tmp/.log/events.txt', '/tmp/*/events.txt', {dot: true})true
.matchBase: boolean
(デフォルト:false
)true
の場合、スラッシュのないパターンはパスのbasenameと一致します。
> minimatch('/dir/file.txt', 'file.txt')false
> minimatch('/dir/file.txt', 'file.txt', {matchBase: true})true
new minimatch.Minimatch()
:一度コンパイルして複数回照合するminimatch.Minimatch
クラスを使用すると、globを正規表現に一度だけコンパイルして、複数回照合できます。
new Minimatch(pattern: string, options?: MinimatchOptions)
このクラスは次のように使用します。
import minimatch from 'minimatch';
const {Minimatch} = minimatch;
const glob = new Minimatch('/dir/sub/*.txt');
.equal(
assert.match('/dir/sub/file.txt'), true
glob;
).equal(
assert.match('/dir/sub/notes.txt'), true
glob; )
このセクションでは、構文の基本事項について説明します。しかし、さらに多くの機能があります。これらはここに記載されています。
Windowsでも、globセグメントはスラッシュで区切られますが、バックスラッシュとスラッシュの両方と一致します(Windowsでは有効なパス区切り文字です)。
> minimatch('dir\\sub/file.txt', 'dir/sub/file.txt')true
Minimatchはパスを自動的に正規化しません。
> minimatch('./file.txt', './file.txt')true
> minimatch('./file.txt', 'file.txt')false
> minimatch('file.txt', './file.txt')false
したがって、自分で作成しない場合は、パスを正規化する必要があります。
> path.normalize('./file.txt')'file.txt'
ワイルドカード記号(より柔軟に一致する)のないパターンは、正確に一致する必要があります。特に、パス区切り文字は一致する必要があります。
> minimatch('/dir/file.txt', '/dir/file.txt')true
> minimatch('dir/file.txt', 'dir/file.txt')true
> minimatch('/dir/file.txt', 'dir/file.txt')false
> minimatch('/dir/file.txt', 'file.txt')false
つまり、絶対パスか相対パスのどちらかを選択する必要があります。
.matchBase
オプションを使用すると、スラッシュのないパターンをパスのbasenameと照合できます。
> minimatch('/dir/file.txt', 'file.txt', {matchBase: true})true
*
)は、単一のセグメントの任意の部分と一致しますワイルドカード記号であるアスタリスク(*
)は、任意のパスセグメントまたはセグメントの任意の部分と一致します。
> minimatch('/dir/file.txt', '/*/file.txt')true
> minimatch('/tmp/file.txt', '/*/file.txt')true
> minimatch('/dir/file.txt', '/dir/*.txt')true
> minimatch('/dir/data.txt', '/dir/*.txt')true
アスタリスクは、名前がドットで始まる「非表示ファイル」とは一致しません。それらを一致させたい場合は、アスタリスクの前にドットを付ける必要があります。
> minimatch('file.txt', '*')true
> minimatch('.gitignore', '*')false
> minimatch('.gitignore', '.*')true
> minimatch('/tmp/.log/events.txt', '/tmp/*/events.txt')false
.dot
オプションを使用して、この動作をオフにできます。
> minimatch('.gitignore', '*', {dot: true})true
> minimatch('/tmp/.log/events.txt', '/tmp/*/events.txt', {dot: true})true
**
)は、0個以上のセグメントと一致します**/
は、0個以上のセグメントと一致します。
> minimatch('/file.txt', '/**/file.txt')true
> minimatch('/dir/file.txt', '/**/file.txt')true
> minimatch('/dir/sub/file.txt', '/**/file.txt')true
相対パスと一致させたい場合でも、パターンはパス区切り文字で始まらないようにする必要があります。
> minimatch('file.txt', '/**/file.txt')false
ダブルアスタリスクは、名前がドットで始まる「非表示」のパスセグメントとは一致しません。
> minimatch('/usr/local/.tmp/data.json', '/usr/**/data.json')false
.dot
オプションを使用して、この動作をオフにできます。
> minimatch('/usr/local/.tmp/data.json', '/usr/**/data.json', {dot: true})true
globを感嘆符で始めると、感嘆符の後のパターンと一致しない場合に一致します。
> minimatch('file.txt', '!**/*.txt')false
> minimatch('file.js', '!**/*.txt')true
中括弧内のコンマ区切りのパターンは、いずれかのパターンと一致する場合に一致します。
> minimatch('file.txt', 'file.{txt,js}')true
> minimatch('file.js', 'file.{txt,js}')true
ダブルドットで区切られた整数のペアは、整数の範囲を定義し、その要素のいずれかと一致する場合に一致します。
> minimatch('file1.txt', 'file{1..3}.txt')true
> minimatch('file2.txt', 'file{1..3}.txt')true
> minimatch('file3.txt', 'file{1..3}.txt')true
> minimatch('file4.txt', 'file{1..3}.txt')false
ゼロパディングもサポートされています。
> minimatch('file1.txt', 'file{01..12}.txt')false
> minimatch('file01.txt', 'file{01..12}.txt')true
> minimatch('file02.txt', 'file{01..12}.txt')true
> minimatch('file12.txt', 'file{01..15}.txt')true
file:
URLの使用Node.jsでファイルを参照する一般的な方法は2つあります。
file:
であるURL
のインスタンス例:
.equal(
assert.readFileSync(
fs'/tmp/data.txt', {encoding: 'utf-8'}),
'Content'
;
).equal(
assert.readFileSync(
fsnew URL('file:///tmp/data.txt'), {encoding: 'utf-8'}),
'Content'
; )
URL
クラスこのセクションでは、URL
クラスを詳しく見ていきます。このクラスの詳細については、
この章では、他のWebプラットフォームで使用されている方法と同じように、グローバル変数経由でURL
クラスにアクセスします。しかし、インポートすることもできます。
import {URL} from 'node:url';
URLはURIのサブセットです。URIの標準であるRFC 3986では、2種類のURI参照が区別されています。
URL
のコンストラクタURL
クラスは2つの方法でインスタンス化できます。
new URL(uri: string)
uri
はURIである必要があります。新しいインスタンスのURIを指定します。
new URL(uriRef: string, baseUri: string)
baseUri
はURIである必要があります。uriRef
が相対参照の場合、baseUri
に対して解決され、その結果が新しいインスタンスのURIになります。
uriRef
がURIの場合、インスタンスの基礎となるデータとしてbaseUri
を完全に置き換えます。
ここでは、クラスの動作を確認できます。
// If there is only one argument, it must be a proper URI
.equal(
assertnew URL('https://example.com/public/page.html').toString(),
'https://example.com/public/page.html'
;
).throws(
assert=> new URL('../book/toc.html'),
() /^TypeError \[ERR_INVALID_URL\]: Invalid URL$/
;
)
// Resolve a relative reference against a base URI
.equal(
assertnew URL(
'../book/toc.html',
'https://example.com/public/page.html'
.toString(),
)'https://example.com/book/toc.html'
; )
URL
のインスタンスに対する相対参照の解決URL
コンストラクタのこのバリアントを再検討しましょう。
new URL(uriRef: string, baseUri: string)
引数baseUri
は文字列に変換されます。したがって、文字列に変換したときに有効なURLになる限り、任意のオブジェクトを使用できます。
const obj = { toString() {return 'https://example.com'} };
.equal(
assertnew URL('index.html', obj).href,
'https://example.com/index.html'
; )
これにより、URL
インスタンスに対して相対参照を解決できます。
const url = new URL('https://example.com/dir/file1.html');
.equal(
assertnew URL('../file2.html', url).href,
'https://example.com/file2.html'
; )
このように使用すると、コンストラクタはpath.resolve()
と大まかに似ています。
URL
インスタンスのプロパティURL
のインスタンスには、以下のプロパティがあります。
type URL = {
: string,
protocol: string,
username: string,
password: string,
hostname: string,
port: string,
hostreadonly origin: string,
: string,
pathname
: string,
searchreadonly searchParams: URLSearchParams,
: string,
hash
: string,
hreftoString(): string,
toJSON(): string,
}
URLを文字列に変換する一般的な方法は3つあります。
const url = new URL('https://example.com/about.html');
.equal(
assert.toString(),
url'https://example.com/about.html'
;
).equal(
assert.href,
url'https://example.com/about.html'
;
).equal(
assert.toJSON(),
url'https://example.com/about.html'
; )
.toJSON()
メソッドを使用すると、JSONデータでURLを使用できます。
const jsonStr = JSON.stringify({
pageUrl: new URL('https://exploringjs.dokyumento.jp')
;
}).equal(
assert, '{"pageUrl":"https://exploringjs.dokyumento.jp"}'
jsonStr; )
URL
プロパティを取得するURL
インスタンスのプロパティは、独自のデータプロパティではなく、ゲッターとセッターによって実装されています。次の例では、ユーティリティ関数pickProps()
(コードは最後に示されています)を使用して、これらのゲッターによって返される値をプレーンオブジェクトにコピーします。
const props = pickProps(
new URL('https://jane:pw@example.com:80/news.html?date=today#misc'),
'protocol', 'username', 'password', 'hostname', 'port', 'host',
'origin', 'pathname', 'search', 'hash', 'href'
;
).deepEqual(
assert,
props
{protocol: 'https:',
username: 'jane',
password: 'pw',
hostname: 'example.com',
port: '80',
host: 'example.com:80',
origin: 'https://example.com:80',
pathname: '/news.html',
search: '?date=today',
hash: '#misc',
href: 'https://jane:pw@example.com:80/news.html?date=today#misc'
};
)function pickProps(input, ...keys) {
const output = {};
for (const key of keys) {
= input[key];
output[key]
}return output;
}
残念ながら、パス名は単一の原子単位です。つまり、URL
クラスを使用してその部分(ベース、拡張子など)にアクセスすることはできません。
.hostname
などのプロパティを設定することで、URLの一部を変更することもできます。
const url = new URL('https://example.com');
.hostname = '2ality.com';
url.equal(
assert.href, 'https://2ality.com/'
url; )
セッターを使用して、部分的なURLを作成できます(Haroen Viaeneによるアイデア)。
// Object.assign() invokes setters when transferring property values
const urlFromParts = (parts) => Object.assign(
new URL('https://example.com'), // minimal dummy URL
// assigned to the dummy
parts ;
)
const url = urlFromParts({
protocol: 'https:',
hostname: '2ality.com',
pathname: '/p/about.html',
;
}).equal(
assert.href, 'https://2ality.com/p/about.html'
url; )
.searchParams
による検索パラメータの管理.searchParams
プロパティを使用して、URLの検索パラメータを管理できます。その値は、URLSearchParams
のインスタンスです。
これを使用して、検索パラメータを読み取ることができます。
const url = new URL('https://example.com/?topic=js');
.equal(
assert.searchParams.get('topic'), 'js'
url;
).equal(
assert.searchParams.has('topic'), true
url; )
これを使用して、検索パラメータを変更することもできます。
.searchParams.append('page', '5');
url.equal(
assert.href, 'https://example.com/?topic=js&page=5'
url;
)
.searchParams.set('topic', 'css');
url.equal(
assert.href, 'https://example.com/?topic=css&page=5'
url; )
ファイルパスとURLを手動で変換しようとすることがありますが、例えば、URL
インスタンスmyUrl
をmyUrl.pathname
を介してファイルパスに変換しようとすることができます。しかし、これは必ずしも機能するわけではありません。 この関数を使用する方が良いでしょう。
.fileURLToPath(url: URL | string): string url
次のコードは、その関数の結果と.pathname
の値を比較しています。
import * as url from 'node:url';
//::::: Unix :::::
const url1 = new URL('file:///tmp/with%20space.txt');
.equal(
assert.pathname, '/tmp/with%20space.txt');
url1.equal(
assert.fileURLToPath(url1), '/tmp/with space.txt');
url
const url2 = new URL('file:///home/thor/Mj%C3%B6lnir.txt');
.equal(
assert.pathname, '/home/thor/Mj%C3%B6lnir.txt');
url2.equal(
assert.fileURLToPath(url2), '/home/thor/Mjölnir.txt');
url
//::::: Windows :::::
const url3 = new URL('file:///C:/dir/');
.equal(
assert.pathname, '/C:/dir/');
url3.equal(
assert.fileURLToPath(url3), 'C:\\dir\\'); url
この関数はurl.fileURLToPath()
の逆関数です。
.pathToFileURL(path: string): URL url
これはpath
をファイルURLに変換します。
> url.pathToFileURL('/home/john/Work Files').href'file:///home/john/Work%20Files'
URLの重要なユースケースの1つは、現在のモジュールの兄弟であるファイルにアクセスすることです。
function readData() {
const url = new URL('data.txt', import.meta.url);
return fs.readFileSync(url, {encoding: 'UTF-8'});
}
この関数は、現在のモジュールのURL(通常はNode.jsではfile:
URL)を含むimport.meta.url
を使用します。
fetch()
を使用すると、前のコードはさらにクロスプラットフォームになります。しかし、Node.js 18.9.0時点では、fetch()
はfile:
URLではまだ動作しません。
> await fetch('file:///tmp/file.txt')TypeError: fetch failed
cause: Error: not implemented... yet...
ESMモジュールは2つの方法で使用できます。
モジュールを両方の方法で使用する場合、現在のモジュールがメインモジュールかどうかを確認する必要があります。スクリプト機能を実行するのは、その場合のみだからです。この章では、そのチェックを実行する方法を学習します。
CommonJSでは、次のパターンを使用して、現在のモジュールがエントリポイントであったかどうかを検出できます(ソース:Node.jsドキュメント)。
if (require.main === module) {
// Main CommonJS module
}
現時点では、ESMモジュールには、モジュールがメインかどうかを確認する簡単な組み込み方法がありません。代わりに、次の回避策を使用する必要があります(Rich Harrisによるツイートに基づく)。
import * as url from 'node:url';
if (import.meta.url.startsWith('file:')) { // (A)
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) { // (B)
// Main ESM module
} }
説明
import.meta.url
には、現在実行されているESMモジュールのURLが含まれています。
コードが常にローカルで実行されると確信している場合(将来的にはそれほど一般的ではなくなる可能性があります)、A行のチェックを省略できます。省略してコードがローカルで実行されない場合でも、少なくとも例外が発生します(サイレントエラーにはなりません) - url.fileURLToPath()
のおかげです(次の項目を参照)。
url.fileURLToPath()
を使用して、URLをローカルパスに変換します。この関数は、プロトコルがfile:
でない場合、例外をスローします。
process.argv[1]
には、最初のモジュールのパスが含まれています。B行の比較は、この値が常に絶対パスであるため機能します。Node.jsは次のように設定します(ソースコード)。
process.argv[1] = path.resolve(process.argv[1]);
file:
URLシェルスクリプトがファイルへの参照を受け取ったり、ファイルへの参照をエクスポートしたりする場合(例:画面にログ出力する場合)、それらは事実上常にパスです。ただし、前のセクションで説明したように、URLが必要になるケースが2つあります。