處理檔案用的函式由 File模組提供。
要讀取整個檔案,請使用 File.read/1。要寫入檔案,請使用 File.write/2。
這個模組也提供複製、刪除、重新命名等檔案相關函式。它們的名稱和 UNIX 中對應的功能類似,例如:
File.cp/3 - 複製檔案。File.rm/1 - 刪除檔案。File.rename/2 - 重新命名及/或移動檔案。File.mkdir/1 - 建立目錄。File.cwd/0 - 取得目前的工作目錄。上述 File模組中的所有函式都有一個 !版本,這個版本會拋出錯誤,而不是回傳錯誤元組(例如 File.read!/1)。如果你不打算處理檔案不存在或權限不足這類錯誤,就使用這個版本。
File.read("does_not_exist")
# => {:error, :enoent}
File.read!("does_not_exist")
# => ** (File.Error) could not read file "does_not_exist": no such file or directory
# (elixir 1.10.4) lib/file.ex:353: File.read!/1
每次用 File.write/2寫入檔案時,都會開啟一個檔案描述子,並產生一個新的 Elixir 行程。基於這個原因,應該避免在迴圈中用 File.write/2寫入檔案。
取而代之的是,可以用 File.open/2開啟檔案。File.open/2的第二個引數是一串模式,讓你可以指定要以讀取還是寫入的方式開啟檔案。
常用的模式有:
:read - 以讀取模式開啟,檔案必須存在:write - 以寫入模式開啟,檔案不存在時會建立,現有內容會被覆寫:append - 以寫入模式開啟,檔案不存在時會建立,現有內容會保留完整的模式清單請見 File.open/2的文件。
File.open/2會回傳負責處理這個檔案的行程 PID。要讀寫檔案,請使用 IO模組的函式,並把這個 PID 當作 IO 裝置 傳入。
檔案處理完畢後,請用 File.close/1關閉它。
file = File.open!("README.txt", [:write])
# => #PID<0.157.0>
IO.puts(file, "# README")
# => :ok
File.close(file)
# => :ok
用 File.read/1讀取檔案會一次把整個檔案載入記憶體。處理非常大的檔案時,這可能會是個問題。要有效處理這種檔案,你可以使用 File.open/2和 IO.read/2逐行讀取檔案,也可以用 File.stream/3把檔案串流處理。這個串流同時實作了 Enumerable和 Collectable協定,也就是說它既能用來讀取,也能用來寫入。
File.stream!("file.txt")
|> Stream.map(&(&1 <> "!"))
|> Stream.into(File.stream!("new_file.txt"))
|> Stream.run()
所有處理檔案的函式都需要檔案路徑。檔案路徑可以是絕對路徑,也可以是相對於目前目錄的路徑。要操作路徑,請使用 Path模組的函式。為了跨平台相容性,請用 Path.join/1建立路徑,它會選擇適合目前平台的分隔符號。
Path.expand(Path.join(["~", "documents", "important.txt"]))
"/home/user/documents/important.txt"