1. C 語言的open
函數是什麼?
1.1 open
函數的作用
C語言的open
函數是用來開啟或建立檔案的系統呼叫。
一般而言,在 Linux 或 UNIX 系統環境中使用,當需要執行比標準函式庫的fopen
更低階的檔案操作時會被使用。1.2 fopen
函數的差異
C語言中也有用於開啟檔案的標準函式庫函數fopen
,但其用途與open
函數不同。函式 | 特徵 |
---|
open | 低階 API、回傳檔案描述符、系統呼叫 |
fopen | 高階 API、回傳FILE* 、支援緩衝 |
open
函數的用途- 記錄日誌檔案(使用
O_APPEND
) - 建立暫存檔案(
O_TMPFILE
) - 非同步處理(
O_NONBLOCK
) - 建立具有特定存取權限的檔案(
O_CREAT
+ mode
)
如此,open
函數可用於從簡單的檔案操作到高階的檔案管理,應用範圍廣泛。
2. open
函式的基本使用方式【附範例程式碼】
2.1 open
函式的原型
open
函式在 fcntl.h
標頭檔中定義,以下如所示。#include <fcntl.h>
int open(const char *path, int flags, mode_t mode);
path
:要開啟的檔案路徑(例如:"sample.txt"
)。flags
:指定檔案開啟模式與行為的旗標(例如:O_RDONLY
)。mode
:檔案建立時的權限(在指定 O_CREAT
時需要)。- 返回值:
- 成功時:檔案描述符(
0
以上的整數) - 失敗時:返回
-1
,錯誤資訊存於 errno
。
2.2 open
函式的基本使用方式
以下範例示範以讀寫模式(O_RDWR
)開啟檔案,若需新建則以 0644
權限建立。#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("sample.txt", O_RDWR | O_CREAT, 0644);
if (fd == -1) {
perror("open");
return 1;
}
printf("File opened successfully with descriptor %dn", fd);
close(fd);
return 0;
}
2.3 open
函式的錯誤處理
open
函式失敗時,會返回 -1
,錯誤代碼會存於全域變數 errno
。
使用 perror()
可以清楚顯示錯誤內容。#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main() {
int fd = open("/root/protected.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
return 1;
}
close(fd);
return 0;
}
錯誤代碼範例:EACCES
(Permission denied):權限不足ENOENT
(No such file or directory):指定的檔案不存在
2.4 open
函式的選項活用
int fd = open("sample.txt", O_RDONLY);
int fd = open("sample.txt", O_WRONLY);
int fd = open("sample.txt", O_WRONLY | O_CREAT, 0644);
int fd = open("sample.txt", O_WRONLY | O_TRUNC);

3. open
函式的旗標列表【完整指南】
3.1 基本的旗標
3.1.1 指定讀寫模式的旗標
旗標 | 說明 |
---|
O_RDONLY | 以唯讀方式開啟 |
O_WRONLY | 以唯寫方式開啟 |
O_RDWR | 以可讀寫的模式開啟 |
3.1.2 使用範例
int fd1 = open("file.txt", O_RDONLY); // 以唯讀方式
int fd2 = open("file.txt", O_WRONLY); // 以唯寫方式
int fd3 = open("file.txt", O_RDWR); // 可讀寫
3.2 關於檔案建立與管理的旗標
3.2.1 O_CREAT
(檔案不存在時新建)
int fd = open("newfile.txt", O_WRONLY | O_CREAT, 0644);
3.2.2 O_EXCL
(與 O_CREAT
同時使用,若檔案已存在則錯誤)
int fd = open("newfile.txt", O_WRONLY | O_CREAT | O_EXCL, 0644);
if (fd == -1) {
perror("File already exists");
}
3.2.3 O_TRUNC
(開啟已存在的檔案時刪除內容)
int fd = open("log.txt", O_WRONLY | O_TRUNC);
3.3 控制寫入行為的旗標
3.3.1 O_APPEND
(以追加模式開啟)
int fd = open("log.txt", O_WRONLY | O_APPEND);
write(fd, "New log entryn", 14);
3.4 控制非同步/特殊行為的旗標
3.4.1 O_NONBLOCK
(非阻塞模式)
int fd = open("fifo_pipe", O_RDONLY | O_NONBLOCK);
3.4.2 O_SYNC
(同步寫入)
int fd = open("important_data.txt", O_WRONLY | O_SYNC);
3.4.3 O_NOFOLLOW
(不追蹤符號連結)
int fd = open("symlink_file", O_RDONLY | O_NOFOLLOW);
3.5 旗標的組合
目的 | 旗標的組合 |
---|
可讀寫 + 新建 | O_RDWR | O_CREAT, 0644 |
唯寫 + 追加模式 | O_WRONLY | O_APPEND |
唯讀 + 非同步處理 | O_RDONLY | O_NONBLOCK |
開啟檔案並清空內容 | O_WRONLY | O_TRUNC |
僅在檔案不存在時新建 | O_WRONLY | O_CREAT | O_EXCL, 0644 |
4. mode
(檔案權限)的詳細
4.1 mode
是什麼?
mode
是,在使用 open
函式建立新檔案時(使用 O_CREAT
標誌),用來指定檔案存取權限的值。int fd = open("newfile.txt", O_WRONLY | O_CREAT, 0644);
4.2 mode
的基本設定
權限值 | 存取權限 | 意義 |
---|
0 (無) | --- | 不可存取 |
1 (執行) | --x | 僅執行 |
2 (寫入) | -w- | 僅寫入 |
4 (讀取) | r-- | 僅讀取 |
6 (讀取+寫入) | rw- | 讀取與寫入 |
7 (全部允許) | rwx | 讀取、寫入、執行 |
4.3 mode
與umask
的關係
在 UNIX 系統中,mode
的指定值不會直接套用,而是受到 umask
(使用者遮罩)的影響。0666(指定的mode)
- 0022(umask)
------------
0644(實際套用的權限)
確認目前的 umask
:$ umask
0022
4.4 使用 chmod
變更權限
如果想在建立後變更權限,請使用 chmod
指令。$ chmod 600 secret.txt # 秘密檔案
$ chmod 755 script.sh # 可執行檔案
在 C 語言中使用 chmod
時:#include <sys/stat.h>
chmod("file.txt", 0644);
4.5 考慮 mode
的 open
函式實作範例
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("secure.txt", O_WRONLY | O_CREAT, 0600);
if (fd == -1) {
perror("開啟失敗");
return 1;
}
printf("File created successfully with descriptor %dn", fd);
close(fd);
return 0;
}
5. open
函式與相關的系統呼叫
5.1 close
函式(關閉檔案)
5.1.1 close
的原型
#include <unistd.h>
int close(int fd);
5.1.2 close
的使用範例
#include <fcntl.h>#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("sample.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
return 1;
}
printf("File opened successfully.n");
if (close(fd) == -1) {
perror("close failed");
return 1;
}
printf("File closed successfully.n");
return 0;
}
5.2 read
函式
6. open
函式的實務使用範例
6.1 以追加模式開啟記錄檔
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0644);
if (fd == -1) {
perror("open failed");
return 1;
}
const char *log_entry = "New log entryn";
write(fd, log_entry, 14);
close(fd);
return 0;
}
6.2 建立暫存檔
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("/tmp", O_TMPFILE | O_RDWR, 0644);
if (fd == -1) {
perror("open failed");
return 1;
}
const char *data = "Temporary datan";
write(fd, data, 15);
printf("Temporary file created (fd = %d)n", fd);
close(fd);
return 0;
}
6.3 使用 O_NONBLOCK
的非同步處理
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("fifo_pipe", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open failed");
return 1;
}
printf("File opened in non-blocking moden");
close(fd);
return 0;
}
6.4 錯誤處理的實作
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main() {
int fd = open("/root/protected.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
if (errno == EACCES) {
printf("Permission deniedn");
} else if (errno == ENOENT) {
printf("File does not existn");
}
return 1;
}
close(fd);
return 0;
}
6.5 利用 lseek
變更檔案位置
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("sample.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
return 1;
}
lseek(fd, 10, SEEK_SET);
char buffer[11];
read(fd, buffer, 10);
buffer[10] = '�';
printf("Read after seek: %sn", buffer);
close(fd);
return 0;
}
7. open
函數相關的常見問題(FAQ)
7.1 open
函數與fopen
函數的差異是?
函式 | 特徵 | 用途 |
---|
open | 系統呼叫,回傳檔案描述符(整數) | 低階檔案操作、系統程式設計 |
fopen | 標準 C 函式庫,回傳 FILE* | 利用緩衝的通用檔案 I/O |
7.2 open
函數中mode
是否必須指定?
int fd = open("newfile.txt", O_WRONLY | O_CREAT, 0644);
7.3 指定 O_APPEND
後,寫入位置是否永遠在檔案末端?
- 是的,指定
O_APPEND
後寫入會永遠在檔案末端進行
int fd = open("log.txt", O_WRONLY | O_APPEND);
write(fd, "New entryn", 10);
close(fd);
7.4 什麼時候使用 O_NONBLOCK
旗標?
- 在 FIFO(管道)或 socket 想要立即返回的情況
int fd = open("fifo_pipe", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open failed");
}
7.5 用 open
函數開啟符號連結會發生什麼?
- 通常會開啟連結指向的檔案,但使用
O_NOFOLLOW
可以防止
int fd = open("symlink.txt", O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
perror("open failed");
}
7.6 如何使用 open
函數取得檔案大小?
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("sample.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
return 1;
}
off_t filesize = lseek(fd, 0, SEEK_END);
printf("File size: %ld bytesn", filesize);
close(fd);
return 0;
}
7.7 open
函數失敗的主要原因是?
錯誤代碼 | 意義 |
---|
EACCES | 沒有存取權限 |
ENOENT | 檔案不存在 |
EEXIST | 使用 O_CREAT | O_EXCL 時已有檔案存在 |
EMFILE | 超過行程可開啟檔案數量上限 |
ENOSPC | 磁碟空間不足 |
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main() {
int fd = open("/root/protected.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
if (errno == EACCES) {
printf("Permission deniedn");
} else if (errno == ENOENT) {
printf("File does not existn");
}
return 1;
}
close(fd);
return 0;
}
8. 總結
8.1 open
函式的基本
open
函式是用來開啟或建立檔案的系統呼叫。- 與
fopen
不同,會回傳檔案描述符(FD)。 - 適當執行
close(fd)
,以防止資源洩漏。
8.2 open
函式的主要旗標
旗標 | 說明 |
---|
O_RDONLY | 以唯讀方式開啟 |
O_WRONLY | 以唯寫方式開啟 |
O_RDWR | 以可讀寫模式開啟 |
O_CREAT | 若檔案不存在則新建 |
O_TRUNC | 刪除已存在檔案的內容 |
O_APPEND | 寫入時總是追加至檔案尾端 |
O_NONBLOCK | 非阻塞模式 |
O_NOFOLLOW | 不開啟符號連結 |
8.3 open
函式與相關的系統呼叫
close(fd)
:釋放檔案描述符。read(fd, buf, count)
:從檔案讀取資料。write(fd, buf, count)
:寫入資料至檔案。lseek(fd, offset, whence)
:移動檔案的讀寫位置。
8.4 open
函式的實務使用範例
- 日誌檔案的追加 → 使用
O_APPEND
追加至尾端。 - 暫存檔案的建立 → 活用
O_TMPFILE
。 - 非同步處理 → 使用
O_NONBLOCK
以避免阻塞。
8.5 open
函式的注意事項
- 適當地呼叫
close(fd)
:為防止資源洩漏。 - 執行錯誤處理:檢查
errno
,並採取適當的對策。 - 不要設定錯誤的權限:若
mode
指定錯誤,會造成安全風險。
8.6 本文的總結
章節 | 內容 |
---|
open 函式的基本 | 用於低階檔案操作的系統呼叫 |
open 函式的使用方式 | 使用 O_CREAT 時需要 mode |
open 的主要旗標 | O_RDONLY , O_WRONLY , O_RDWR , O_CREAT , etc. |
相關系統呼叫 | close , read , write , lseek |
實務使用範例 | 日誌記錄、暫存檔案、非同步處理、錯誤處理 |
常見問答 | 與 fopen 的差異、O_APPEND 的運作、錯誤處理 |
8.7 最後
C語的open
函式是系統層級的檔案操作不可或缺的系統呼叫。適當使用可實現高效的檔案管理與非同步處理。請活用本文所學的知識,開發安全且堅固的程式。