當用 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 執行的權限

例如,當你建立檔案的時候,沒有給使用者讀取的權限,此時該使用者會出現拒絕存取的訊息。如下圖。

Permission deniedPermission denied

perm FileMode 使用方式

從文件看來 FileModetype FileMode uint32,就只是一個數字。
幸好 FileMode 有 func (FileMode) String 方法,所以我們可以將它印出來看看。 例如,執行下列程式碼會印出 -rwx------

Print FileMode
  • go
1
2
3
4
5
6
7
8
9
10
package main

import (
"fmt"
"os"
)

func main() {
fmt.Println(os.FileMode(0700))
}

有哪些使用者可以設定權限?

以檔案來說,在 unix-like 系統,會分三種不同級別的使用者

  • 檔案的擁有者,預設是檔案建立人
  • 特定群組使用者
  • 其他使用者(非上述的兩種使用者)

所以我們看回來 -rwx------ 這代表是什麼含意? 在什麼權限都沒設定設定情況下,例如 fmt.Println(os.FileMode(0000)) 會印出 10 個 dash ----------。 我們先撇除第一個 dash 不要看,我們可以把剩下 9 個 dash 分成三組,這就代表三種不同級別使用者的權限。
請參考下圖說明,前 3 個 dash 代表擁有者的權限、中間 3 個 dash 代表群組使用者的權限、最後 3 個 dash 代表其他使用者的權限。

diff-usersdiff-users

所以讀者應該就可以發現,每一個權限只要 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

directory sample
  • go
1
2
3
4
func 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]