---
tags: sp
---
# 檔案的輸入輸出
## file
- file hole
- 值為0,但不會佔據實際空間
- 可用 lseek 製造
- 檔案指標
- 代表目前在對該位置做操作
- 改變檔案指標位置:read、write、lseek
## open & close file
### 代號
- 0: stdin
- 1: stdout(有優化/有buf)
- 2: stderr (無buf)
### open file
headerfile: `#include <fcntl.h>`
用法: `int open(const char *pathname, int flags);` or `int open(const char *pathname, int flags, mode_t mode);`
- 回傳值:file descriptor(可用的最小數字),-1為錯誤
- flags:
`O_RDONLY` 讀、`O_WRONLY` 寫、`O_RDWR` 讀寫 (三者需擇一)
`O_CREAT` 製造檔案 (選用)
`O_APPEND` 資料加到檔案最後面
`O_TRUNC` 將檔案大小歸0,可以保證不會有舊資料
`O_CLOEXEC` 使用execve時自動關閉檔案
- mode:
`S_IRWXU` 檔案擁有者可讀、寫、執行
`S_IRUSR` 檔案擁有者可讀
`S_IWUSR` 檔案擁有者可寫
`S_IXUSR` 檔案擁有者可執行
- ex : `open(fileName,O_RDONLY);`
### close file
`int close(int fd)`
- 回傳值:0為成功,-1為錯誤
- 可以讓作業系統釋放資源
- ex : `close(fileFd)`
## file IO
header file: `#include <unistd.h>`
### read
用法: `ssize_t read(int fd, void *buf, size_t len)`
- 從 fd 讀 len 個位元組到 buf
- 回傳值:成功回傳讀到的位元組數(EOF為0),錯誤回傳-1
### write
用法: `ssize_t write(int fd, const void *buf, size_t len);`
- 從 buf 寫 len 個位元組到 fd
- 回傳值:成功回傳寫入的位元組數,錯誤回傳-1
- 不支援file hole(會用0填滿)
### perror
用法: `void perror(const char *s);`
- 印出字串 **s** 後還會印出os的詳細訊息(errno)
> erron :
系統內的錯誤訊息代碼,發生錯誤時會把錯誤寫入
### lseek
改變檔案指標位置
header file: `#include <unistd.h>`
用法: `off_t lseek(fd, offset, WHENCE)`
- offset : 偏移量
- WHENCE : 從哪開始偏移,參數有: SEEK_SET(檔案最一開始), SEEK_CUR(現在位子), SEEK_END(檔案結尾))
- 回傳值:回傳現在位子(從檔案開始的偏移值)(錯誤:回傳-1,errno為1)
- ex : `lseek(fd,0,SEEK_END);` 從後面算起0個
- 進階用法
`#define _GNU_SOURSE`
`off_t lseek(fd, offset, WHENCE)`
- WHENCE多增加 SEEK_DATA(下一個有資料的位子), SEED_HOLE(下一個hole的位子)
- 為虛擬指標偏移,不影響os
## copy file
### method 1: 使用 read, write
- hole會用0取代,檔案會變大
### method 2: 使用 SEEK_DATA , SEED_HOLE
- 可製造出 hole
## sync
- `void sync(void);` 把全部資料(包含meta-data)寫回硬碟
- `int fsync(int fd);` 將fd代表的檔案(包含meta-data)寫回硬碟
- `int fdatasync(int fd);` 將fd代表的檔案(不包含meta-data)寫回硬碟(速度較快)
> meta-data :
ex : 修改日期、檔案大小等
## lock
### flock 良心鎖 (advisory locking)
整個檔案全部上鎖,可多人同時讀
`#include<sys/file.h>`
`int flock(int fd, int operation);`
- operation:
`LOCK_SH` (share) 可以多個人同時(共享鎖)
`LOCK_EX` (exclusive) 只能一人(排他鎖)
`LOCK_UN` (unlock)
- 回傳值:0為成功,-1為錯誤 (錯誤程式碼存於errno)
### lockf 強制鎖 (mandatory locking)
可以對檔案的一部份上鎖,只能一人讀(只有排他鎖,無共享鎖)
`#include<sys/file.h>`
`int lockf(int fd, int cmd, off_t len);`
- cmd:
`F_LOCK` 加鎖
`F_ULOCK` 解鎖
`F_TEST` 測試是否被上鎖,沒被上鎖回傳0,被上鎖回傳-1
- len: 從當前位置開始要上鎖的長度(byte)
- 回傳值:0為成功,-1為錯誤(錯誤程式碼存於errno)
>使用強制鎖前需先下以下指令:
`sudo mount -oremount.mand /` 啟動強制鎖
`chmod g+s filename`
`chmod g-x filename`