穩定性: 3 - 穩定
文件系統模塊是一個封裝了標準的 POSIX 文件 I/O 操作的集合。通過 require('fs')
使用這個模塊。所有的方法都有同步和異步兩種模式。
異步方法最后一個參數都是回調函數,這個回調的參數取決于方法,不過第一個參數一般都是異常。如果操作成功,那么第一個參數就是 null
或 undefined
。
當使用一個同步操作的時候,任意的異常都立即拋出,可以用 try/catch 來處理異常,使得程序正常運行。
這是異步操作的例子:
var fs = require('fs');
fs.unlink('/tmp/hello', function (err) {
if (err) throw err;
console.log('successfully deleted /tmp/hello');
});
這是同步操作的例子:
var fs = require('fs');
fs.unlinkSync('/tmp/hello');
console.log('successfully deleted /tmp/hello');
異步方法不能保證操作順序,因此下面的例子很容易出錯:
fs.rename('/tmp/hello', '/tmp/world', function (err) {
if (err) throw err;
console.log('renamed complete');
});
fs.stat('/tmp/world', function (err, stats) {
if (err) throw err;
console.log('stats: ' + JSON.stringify(stats));
});
可能先執行了 fs.stat
方法。正確的方法:
fs.rename('/tmp/hello', '/tmp/world', function (err) {
if (err) throw err;
fs.stat('/tmp/world', function (err, stats) {
if (err) throw err;
console.log('stats: ' + JSON.stringify(stats));
});
});
在繁忙的進程里,強烈建議使用異步方法。同步方法會阻塞整個進程,直到方法完成。
可能會用到相對路徑,路徑是相對 process.cwd()
來說的。
大部分 fs 函數會忽略回調參數,如果忽略,將會用默認函數拋出異常。如果想得到原調用點的堆棧信息,需要設置環境變量 NODE_DEBUG;
$ cat script.js
function bad() {
require('fs').readFile('/');
}
bad();
$ env NODE_DEBUG=fs node script.js
fs.js:66
throw err;
^
Error: EISDIR, read
at rethrow (fs.js:61:21)
at maybeCallback (fs.js:79:42)
at Object.fs.readFile (fs.js:153:18)
at bad (/path/to/script.js:2:17)
at Object.<anonymous> (/path/to/script.js:5:1)
<etc.>
異步函數 rename(2)。回調函數只有一個參數:可能出現的異常。
同步函數 rename(2)。 返回 undefined
。
異步函數 ftruncate(2)。 回調函數只有一個參數:可能出現的異常。
同步函數 ftruncate(2)。 返回 undefined
。
異步函數 truncate(2)。 回調函數只有一個參數:可能出現的異常。 文件描述符也可以作為第一個參數,如果這種情況,調用 fs.ftruncate()
。
同步函數 truncate(2)。 返回 undefined
。
異步函數 chown(2)。 回調函數只有一個參數:可能出現的異常。
同步函數 chown(2)。 返回 undefined
。
異步函數 fchown(2)。 回調函數只有一個參數:可能出現的異常。
同步函數 fchown(2)。 返回 undefined
。
異步函數 lchown(2)。 回調函數只有一個參數:可能出現的異常。
同步函數 lchown(2)。 返回 undefined
。
異步函數 chmod(2)。回調函數只有一個參數:可能出現的異常。
同步函數 chmod(2)。 返回 undefined
。
異步函數 fchmod(2)。 回調函數只有一個參數:可能出現的異常。
同步函數 fchmod(2)。 返回 undefined
。
異步函數 lchmod(2)。 回調函數只有一個參數:可能出現的異常。
僅在 Mac OS X 可用。
同步函數 lchmod(2)。 返回 undefined
。
異步函數 stat(2)。 回調函數有兩個參數: (err, stats) ,其中 stats
是一個 fs.Stats
對象。 詳情請參考 fs.Stats。
異步函數 lstat(2)。 回調函數有兩個參數: (err, stats) ,其中 stats
是一個 fs.Stats
對象。 lstat()
與 stat()
基本相同, 區別在于,如果 path
是鏈接,讀取的是鏈接本身,而不是它所鏈接到的文件。
異步函數 fstat(2)。 回調函數有兩個參數: (err, stats) ,其中 stats
是一個 fs.Stats
對象。
同步函數 stat(2)。 返回 fs.Stats
實例。
同步函數 lstat(2)。 返回 fs.Stats
實例。
同步函數 fstat(2)。 返回 fs.Stats
實例。
異步函數 link(2)。 回調函數只有一個參數:可能出現的異常。
同步函數 link(2)。 返回 undefined
。
異步函數 symlink(2)。 回調函數只有一個參數:可能出現的異常。
type
可能是 'dir'
, 'file'
, 或 'junction'
(默認 'file'
) ,僅在 Windows(不考慮其他系統)有效。注意, Windows junction 要求目的地址需要絕對的。當使用 'junction'
的時候,destination
參數將會自動轉換為絕對路徑。
同步函數 symlink(2)。 返回 undefined
。
異步函數 readlink(2)。 回調函數有2個參數 (err, linkString)
.
同步函數 readlink(2)。 返回符號鏈接的字符串值。
異步函數 realpath(2)。 回調函數有2個參數 (err,resolvedPath)
。可以使用 process.cwd
來解決相對路徑問題。
例如:
var cache = {'/etc':'/private/etc'};
fs.realpath('/etc/passwd', cache, function (err, resolvedPath) {
if (err) throw err;
console.log(resolvedPath);
});
同步函數 realpath(2)。 返回解析出的路徑。
異步函數 unlink(2)。 回調函數只有一個參數:可能出現的異常.
同步函數 unlink(2)。 返回 undefined
。
異步函數 rmdir(2)。 回調函數只有一個參數:可能出現的異常.
同步函數 rmdir(2)。 返回 undefined
。
異步函數 mkdir(2)。 回調函數只有一個參數:可能出現的異常. mode
默認s to 0777
.
同步函數 mkdir(2)。 返回 undefined
。
異步函數 readdir(3)。 讀取文件夾的內容。回調有2個參數 (err, files)
files 是文件夾里除了名字為,
'.'和
'..'`之外的所有文件名。
同步函數 readdir(3)。 返回除了文件名為 '.'
和 '..'
之外的所有文件.
異步函數 close(2)。 回調函數只有一個參數:可能出現的異常.
同步函數 close(2)。 返回 undefined
。
異步函數 file open. 參見 open(2)。 flags
是:
'r'
- 以只讀模式打開.如果文件不存在,拋出異常。
'r+'
-以讀寫模式打開.如果文件不存在,拋出異常。
'rs'
- 同步的,以只讀模式打開. 指令繞過操作系統直接使用本地文件系統緩存。這個功能主要用來打開 NFS 掛載的文件,因為它能讓你跳過可能過時的本地緩存。如果對 I/O 性能很在乎,就不要使用這個標志位。
這里不是調用 fs.open()
變成同步阻塞請求,如果你想要這樣,可以調用 fs.openSync()
。
'rs+'
- 同步模式下以讀寫方式打開文件。注意事項參見 'rs'
.
'w'
- 以只寫模式打開。文件會被創建 (如果文件不存在) 或者覆蓋 (如果存在)。
'wx'
- 和 'w'
類似,如果文件存儲操作失敗
'w+'
- 以可讀寫方式打開。文件會被創建 (如果文件不存在) 或者覆蓋 (如果存在)
'wx+'
- 和 'w+'
類似,如果文件存儲操作失敗。
'a'
- 以附加的形式打開。如果文件不存在則創建一個。
'ax'
- 和 'a'
類似,如果文件存儲操作失敗。
'a+'
- 以只讀和附加的形式打開文件.若文件不存在,則會建立該文件
'ax+'
- 和 'a+'
類似,如果文件存儲操作失敗.如果文件存在,參數mode
設置文件模式 (permission 和 sticky bits)。 默認是 0666
, 可讀寫.
回調有2個參數 (err, fd)
.
排除標記 'x'
(對應 open(2)的O_EXCL
標記) 保證 path
是新創建的。在 POSIX 系統里,即使文件不存在,也會被認定為文件存在。 排除標記不能確定在網絡文件系統中是否有效。
Linux系統里,無法對以追加模式打開的文件進行指定位置寫。系統核心忽略了位置參數,每次把數據寫到文件的最后。
fs.open()
的同步版本. 返回整數形式的文件描述符。.
改變指定路徑文件的時間戳。
fs.utimes()
的同步版本. 返回 undefined
。
改變傳入的文件描述符指向文件的時間戳。
fs.futimes()
的同步版本. 返回 undefined
。
異步函數 fsync(2)。 回調函數只有一個參數:可能出現的異常.
同步 fsync(2)。 返回 undefined
。
將 buffer
寫到 fd
指定的文件里。
參數 offset
和 length
確定寫哪個部分的緩存。
參數 position
是要寫入的文件位置。如果 typeof position !== 'number'
,將會在當前位置寫入。參見 pwrite(2)。
回調函數有三個參數 (err, written, buffer)
,written
指定 buffer
的多少字節用來寫。
注意,如果 fs.write
的回調還沒執行,就多次調用 fs.write
,這樣很不安全。因此,推薦使用 fs.createWriteStream
。
Linux系統里,無法對以追加模式打開的文件進行指定位置寫。系統核心忽略了位置參數,每次把數據寫到文件的最后。
將 buffer
寫到 fd
指定的文件里。如果 data
不是 buffer,那么它就會被強制轉換為字符串。
參數 position
是要寫入的文件位置。如果 typeof position !== 'number'
,將會在當前位置寫入。參見 pwrite(2)。
參數 encoding
:字符串的編碼方式.
回調函數有三個參數 (err, written, buffer)
,written
指定 buffer
的多少字節用來寫。注意寫入的字節(bytes)和字符(string characters)不同。參見Buffer.byteLength。
和寫入 buffer
不同,必須寫入整個字符串,不能截取字符串。這是因為返回的字節的位移跟字符串的位移是不一樣的。
注意,如果 fs.write
的回調還沒執行,就多次調用 fs.write
,這樣很不安全。因此,推薦使用 fs.createWriteStream
Linux系統里,無法對以追加模式打開的文件進行指定位置寫。系統核心忽略了位置參數,每次把數據寫到文件的最后。
fs.write()
的同步版本. 返回要寫的bytes數.
讀取 fd
指定文件的數據。
buffer
是緩沖區,數據將會寫入到這里.
offset
寫入的偏移量
length
需要讀的文件長度
position
讀取的文件起始位置,如果是 position
是 null
, 將會從當前位置讀。
回調函數有3個參數, (err, bytesRead, buffer)
.
fs.read
的同步版本. 返回 bytesRead
的數量.
filename
{String}options
{Object}encoding
{String | Null} 默認 = null
flag
{String} 默認 = 'r'
callback
{Function}異步讀取整個文件的內容。例如:
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});
回調函數有2個參數 (err, data)
, 參數 data
是文件的內容。如果沒有指定參數 encoding
, 返回原生 buffer
fs.readFile
的同步版本. 返回整個文件的內容.
如果沒有指定參數 encoding
, 返回buffer。
filename
{String}data
{String | Buffer}options
{Object}encoding
{String | Null} 默認 = 'utf8'
mode
{Number} 默認 = 438
(aka 0666
in Octal)flag
{String} 默認 = 'w'
callback
{Function}異步寫文件,如果文件已經存在則替換。 data
可以是緩存或者字符串。
如果參數 data
是 buffer,會忽略參數 encoding
。默認值是 'utf8'
。
列如:
fs.writeFile('message.txt', 'Hello Node', function (err) {
if (err) throw err;
console.log('It\'s saved!');
});
fs.writeFile
的同步版本. 返回 undefined
。
filename
{String}data
{String | Buffer}options
{Object}encoding
{String | Null} 默認 = 'utf8'
mode
{Number} 默認 = 438
(aka 0666
in Octal)flag
{String} 默認 = 'a'
callback
{Function}異步的給文件添加數據,如果文件不存在,就創建一個。 data
可以是緩存或者字符串。
例如:
fs.appendFile('message.txt', 'data to append', function (err) {
if (err) throw err;
console.log('The "data to append" was appended to file!');
});
fs.appendFile
的同步版本. 返回 undefined
。
穩定性: 2 - 不穩定。 盡可能的用 fs.watch 來替換。
監視 filename
文件的變化。每當文件被訪問的時候都會調用listener
。
第二個參數可選。如果有,它必須包含兩個 boolean 參數(persistent
和 interval
)的對象。 persistent
指定文件被監視時進程是否繼續運行。 interval
指定了查詢文件的間隔,以毫秒為單位。缺省值為{ persistent: true, interval: 5007 }。
listener 有兩個參數,第一個為文件現在的狀態,第二個為文件的前一個狀態:
fs.watchFile('message.text', function (curr, prev) {
console.log('the current mtime is: ' + curr.mtime);
console.log('the previous mtime was: ' + prev.mtime);
});
listener中的文件狀態對象類型為 fs.Stat。
如果想修改文件時被通知,而不是訪問的時候就通知,可以比較 curr.mtime
和 prev.mtime
。
穩定性: 2 - 不穩定. 盡可能的用 fs.watch 來替換。
停止監視 filename
文件的變化。如果指定了 listener
,那只會移除這個 listener
。否則,移除所有的 listener,并會停止監視 filename
。
調用 fs.unwatchFile()
停止監視一個沒被監視的文件,不會觸發錯誤,而會發生一個no-op。
穩定性: 2 - 不穩定.
觀察 filename
指定的文件或文件夾的改變。返回對象是 fs.FSWatcher。
第二個參數可選。如果有,它必須是包含兩個 boolean 參數(persistent
和 recursive
)的對象。 persistent
指定文件被監視時進程是否繼續運行。 recursive
表明是監視所有的子文件夾還是當前文件夾,這個參數只有監視對象是文件夾時才有效,而且僅在支持的系統里有效(參見下面注意事項)。
默認值 { persistent: true, recursive: false }
.
回調函數有2個參數 (event, filename)
。event
是 rename
或 change
。filename
是觸發事件的文件名。
fs.watch
API 不是 100% 的跨平臺兼容,可能在某些情況下不可用。
recursive
參數僅在 OS X 上可用。僅 FSEvents
支持這個類型文件的監視,所以未來也不太可能有新的平臺加入。
這些特性依賴于底層系統提供文件系統變動的通知。
inotify
.kqueue
.kqueue
,文件夾使用 FSEvents
.event ports
.ReadDirectoryChangesW
.如果底層系統函數不可用,那么fs.watch
就無法工作。例如,監視網絡文件系統(NFS, SMB, 等)經常不能用。你仍然可以用 fs.watchFile
查詢,但是會比較慢,且不可靠。
回調函數中提供文件名參數,不是每個平臺都能用(Linux 和 Windows 就不行)。即使在可用的平臺,也不能保證都能提供。所以不要假設回調函數中 filename
參數有效,要在代碼里添加一些為空的邏輯判斷。
fs.watch('somedir', function (event, filename) {
console.log('event is: ' + event);
if (filename) {
console.log('filename provided: ' + filename);
} else {
console.log('filename not provided');
}
});
判斷文件是否存在,回調函數參數是 bool 值。例如:
fs.exists('/etc/passwd', function (exists) {
util.debug(exists ? "it's there" : "no passwd!");
});
fs.exists()
是老版本的函數,因此在代碼里不要用。
另外,打開文件前判斷是否存在有漏洞,在fs.exists()
和 fs.open()
調用中間,另外一個進程有可能已經移除了文件。最好用 fs.open()
來打開文件,根據回調函數來判斷是否有錯誤。
fs.exists()
未來會被移除。
fs.exists()
的同步版本. 如果文件存在返回 true
, 否則返回false
。
fs.existsSync()
未來會被移除。
測試由參數 path
指向的文件的用戶權限。可選參數 mode
為整數,它表示需要檢查的權限。下面列出了所有值。mode
可以是單個值,或者可以通過或運算,掩碼運算實現多個權限檢查。
fs.F_OK
- 文件是對于進程可見,可以用來檢查文件是否存在。參數 mode
的默認值。 fs.R_OK
- 文件對于進程是否可讀。fs.W_OK
- 文件對于進程是否可寫。fs.X_OK
- 文件對于進程是否可執行。(Windows系統不可用,執行效果等同fs.F_OK
) 第三個參數是回調函數。如果檢查失敗,回調函數的參數就是響應的錯誤。下面的例子檢查文件/etc/passwd
是否能被當前的進程讀寫。
fs.access('/etc/passwd', fs.R_OK | fs.W_OK, function(err) {
util.debug(err ? 'no access!' : 'can read/write');
});
fs.access
的同步版本. 如果發生錯誤拋出異常,否則不做任何事情。
fs.stat()
, fs.lstat()
和 fs.fstat()
以及同步版本的返回對象。
stats.isFile()
stats.isDirectory()
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink()
(only valid with fs.lstat()
)stats.isFIFO()
stats.isSocket()
對普通文件使用 util.inspect(stats)
,返回的字符串和下面類似:
{ dev: 2114,
ino: 48064969,
mode: 33188,
nlink: 1,
uid: 85,
gid: 100,
rdev: 0,
size: 527,
blksize: 4096,
blocks: 8,
atime: Mon, 10 Oct 2011 23:24:11 GMT,
mtime: Mon, 10 Oct 2011 23:24:11 GMT,
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
atime
, mtime
, birthtime
, 和 ctime
都是 Date 的實例,需要使用合適的方法來比較這些值。通常使用 getTime() 來獲取時間戳(毫秒,從 1 January 1970 00:00:00 UTC 開始算),這個整數基本能滿足任何比較條件。也有一些其他方法來顯示額外信息。更多參見MDN JavaScript Reference
狀態對象(stat object)有以下語義:
atime
訪問時間 - 文件的最后訪問時間. mknod(2)
, utimes(2)
, 和 read(2)
等系統調用可以改變.mtime
修改時間 - 文件的最后修改時間. mknod(2)
, utimes(2)
, 和 write(2)
等系統調用可以改變.ctime
改變時間 - 文件狀態(inode)的最后修改時間. chmod(2)
, chown(2)
,link(2)
, mknod(2)
, rename(2)
, unlink(2)
, utimes(2)
, read(2)
, 和 write(2)
等系統調用可以改變.birthtime
"Birth Time" - 文件創建時間,文件創建時生成。 在一些不提供文件 birthtime 的文件系統中, 這個字段會使用 ctime 或 1970-01-01T00:00Z (ie, unix epoch timestamp 0)來填充。 在 Darwin 和其他 FreeBSD 系統變體中, 也將 atime 顯式地設置成比它現在的 birthtime 更早的一個時間值,這個過程使用了 utimes(2) 系統調用。在 Node v0.12 版本之前, Windows 系統里 ctime 有 birthtime 值. 注意在v.0.12版本中, ctime 不再是"creation time", 而且在Unix系統中,他一直都不是。
返回可讀流對象 (見 Readable Stream
)。
options
默認值如下:
{ flags: 'r',
encoding: null,
fd: null,
mode: 0666,
autoClose: true
}
參數 options
提供 start
和 end
位置來讀取文件的特定范圍內容,而不是整個文件。start
和 end
都在文件范圍里,并從 0 開始, encoding
是 'utf8'
, 'ascii'
, 或 'base64'
。
如果給了 fd
值, ReadStream
將會忽略 path
參數,而使用文件描述,這樣不會觸發任何 open
事件。
如果 autoClose
為 false,即使發生錯誤文件也不會關閉,需要你來負責關閉,避免文件描述符泄露。如果 autoClose
是 true(默認值),遇到 error
或 end
,文件描述符將會自動關閉。
例如,從100個字節的文件里,讀取最少10個字節:
fs.createReadStream('sample.txt', {start: 90, end: 99});
ReadStream
是 Readable Stream。
fd
{Integer} ReadStream 所使用的文件描述符。當創建文件的ReadStream時觸發。
返回一個新的寫對象 (參見 Writable Stream
)。
options
是一個對象,默認值:
{ flags: 'w',
encoding: null,
fd: null,
mode: 0666 }
options 也可以包含一個 start 選項,在指定文件中寫入數據開始位置。 修改而不替換文件需要 flags 的模式指定為 r+ 而不是默值的 w.
和之前的 ReadStream
類似,如果 fd
不為空,WriteStream
將會忽略 path
參數,轉而使用文件描述,這樣不會觸發任何 open
事件。
WriteStream
是 Writable Stream。
fd
{Integer} WriteStream 所用的文件描述符打開 WriteStream file 時觸發。
目前寫入的字節數,不含等待寫入的數據。
fs.watch()
返回的對象就是這個類.
停止觀察 fs.FSWatcher
對象中的更改。
event
{String} fs 改變的類型filename
{String} 改變的文件名 (if relevant/available)當監聽的文件或文件夾改變的時候觸發,參見fs.watch。
error
{Error object}錯誤發生時觸發。