[Go] os.OpenFile 的第三個參數 perm FileMode
當用 Go 操作檔案的時候,很常會用到 os.OpenFile
讀寫檔案,而其中最後一參數 perm FileMode
所代表的含意對於 Windows 使用者來說肯定是黑人問號,例如下列範例,傳入 os.FileMode(0660)
代表什麼意思?
1 | os.OpenFile("file.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.FileMode(0660)) |
如果你也有同樣的困惑,今天這篇文章就是來解答其背後的意義,就讓我們開始吧。
在文章開始前,要先提醒讀者 perm FileMode
此參數在 Windows 作業系統上是沒有作用的,該參數只會在 Unix-like, macOS 系統上發會作用。
0660 是什麼樣的數字?
其實這就只是一種數字表示方式而已,根據 Go 規格書裡面提到數字的呈現方式可以用十進位、二進位、八進位、十六進位。 例如 0B0110
是二進位表示法,代表十進位的 6。 而開頭為0
的時候,代表這是八進位表示法,例如0660
等於十進位 432 。 那為什麼 perm FileMode
都用八進位來呈現? 是有其原因的,讓我們繼續往下看。
perm FileMode 的用途
此參數的用途在於授權系統的使用者是否可以存取檔案,其存取的權限又分三種
- r 讀的權限
- w 寫的權限
- x 執行的權限
例如,當你建立檔案的時候,沒有給使用者讀取的權限,此時該使用者會出現拒絕存取的訊息。如下圖。
perm FileMode 使用方式
從文件看來 FileMode 是 type FileMode uint32
,就只是一個數字。
幸好 FileMode 有 func (FileMode) String 方法,所以我們可以將它印出來看看。 例如,執行下列程式碼會印出 -rwx------
。
- go
1 | package main |
有哪些使用者可以設定權限?
以檔案來說,在 unix-like 系統,會分三種不同級別的使用者
- 檔案的擁有者,預設是檔案建立人
- 特定群組使用者
- 其他使用者(非上述的兩種使用者)
所以我們看回來 -rwx------
這代表是什麼含意? 在什麼權限都沒設定設定情況下,例如 fmt.Println(os.FileMode(0000))
會印出 10 個 dash ----------
。 我們先撇除第一個 dash 不要看,我們可以把剩下 9 個 dash 分成三組,這就代表三種不同級別使用者的權限。
請參考下圖說明,前 3 個 dash 代表擁有者的權限、中間 3 個 dash 代表群組使用者的權限、最後 3 個 dash 代表其他使用者的權限。
所以讀者應該就可以發現,每一個權限只要 3 bits 就可以設定了,這也是為什麼會使用八進為來呈現,因為易讀。 不然的話,也可以傳入十進位的數字,可是這樣可讀性就會非常差。 例如,傳入 os.FileMode(17)
會產生 -----w---x
,這就很難從數字 17 看出是設定什麼樣的權限。
回顧 os.FileMode(0660) 的意義
這邊先整理,0-7 每個數字權限的意義。
八進位數字 | 權限 |
---|---|
0 | 沒有任何權限 |
1 | 可以執行 |
2 | 可以寫 |
3 | 可以寫、可以執行 |
4 | 可以讀 |
5 | 可以讀、可以執行 |
6 | 可以讀、可以寫 |
7 | 可以讀、可以寫、可以執行 |
有了前面講的知識後,我們這邊將 fmt.Println(os.FileMode(0660))
印出來,會看到 -rw-rw----
這樣的權限設定。 這代表什麼?
- 檔案擁有者可以有讀寫的權限
- 群組使用者可以有讀寫的權限
- 其他使用者沒有任何權限
補充第一個 dash 的意義
第一個呈現的如果是 dash 的話,代表這是一個普通含有訊息的檔案。 其他例子像是,如果我是讀取一個資料夾的話,就會呈現 d。 例如,下列程式碼的 FileMode 就會印出 drwxrwxrwx
。1
2
3
4func main() {
fileInfo, _ := os.Stat("my_directory")
fmt.Println(fileInfo.Mode())
}
小結
身為一個 Windows 使用者,當初看到這個寫法的時候,也是黑人問號,而且又因為是在 Windows 上操作,所以根本感受不到他的差別。 但是 Go 身為一個跨平台的語言,這權限設定的知識還是非常重要,不可不瞭解。
最後提醒一下,權限只有在建立檔案的時候會套用,如果檔案已經建立了,就要使用 os.Chmod()
來改變權限。
延伸閱讀
[Head First Go - Appendix A. understanding os.openfile: Opening Files]