【Linux C/C++】 第06講 檔案IO
一 IO的基礎
1.1 認識核心物件
Linux不允許直接訪問核心裝置和記憶體,但可以通過核心系統函式去訪問
對每個核心物件進行編號ID
如果訪問核心物件,只能通過核心ID
程式設計模型:
申請得到一個核心ID
在核心系統函式中使用核心ID得到對應的核心物件資料
1.2 怎麼訪問檔案
使用函式,傳遞一個檔名,系統開啟檔案,載入檔案至核心,返回一個核心ID
使用函式,傳遞核心ID,得到資料
使用函式,傳遞核心ID,告訴系統釋放檔案
ID:檔案描述符,file description(fd)
1.3 每個程式預設開啟三個檔案裝置:
0:標準輸入
1:標準輸出
2:錯誤輸出
1.4 操作檔案描述符
ssize_t write(int fd,
void* buf,//要寫入核心物件的資料
size_t size);//寫入資料的大小
返回:
> 0 實際寫入的資料
-1 寫入錯誤
ssize_t read(int fd,
void* buf,//返回資料的空間
size_t size);//空間大小
返回:
> 0 實際讀取的資料
= 0 碰到檔案結束符號 EOF
-1 讀取錯誤
二 基於檔案的描述符
2.1 獲取/釋放檔案描述符
a.檔案型別
目錄檔案d
普通檔案f
字元裝置檔案c
塊裝置檔案b (/dev/sda 硬碟)
軟連線檔案l
管道檔案p
socket檔案s
b.檔案屬性
2.2 通過檔案描述符讀寫各種資料
2.3 檔案描述符與重定向
三 IO與檔案對映
3.1 IO的共享與效率
read與write其中資料緩衝的大小
讀取資料的緩衝:getpagesize
3.2 定位與定位讀取
read與write在操作的時候,自動移動讀取位置
lseek改變讀取位置
pread/pwrite 在指定的位置讀寫資料,改變讀寫位置
pread == lseek + read
pwrite == lseek + write
3.3 檔案的其他操作
fstat 獲取檔案狀態
ftruncate 改變檔案大小
3.4 檔案對映
虛擬地址對映到記憶體
虛擬地址可以對映到檔案:可以用記憶體的方式讀寫檔案
mmap/munmap
案例:
1.使用記憶體方式寫入資料
2.使用記憶體方式讀取資料
四 檔案描述符的操作(IO鎖)
檔案描述符是整數
檔案描述符對應核心的上下文
4.1 dup dup2 拷貝檔案描述符
4.2 fcntl對檔案描述符的屬性的修改
4.2.1 拷貝檔案描述符
4.2.2 修改判定檔案的描述標記
4.2.3 修改判定檔案的狀態標記
不可修改 O_RDONLY O_WRONLY O_RDWR O_CREAT O_EXCL
可修改 O_APPEND O_ASYN非同步方式
4.2.4 設定強制鎖 (重新編譯核心)
4.2.5 設定建議鎖(預設)
4.2.6 設定IO的訊號
檔案IO例項:
socket_server_send是對send函式的一個封裝,讀者可以自行實現
//讀取指定檔案並傳送到客戶端
void SendFile(const char* filename,int conn_id)
{
int fd=0;
char path[256]={0};
int loc=0;
sprintf(path,"./file/%s",filename);
fd = open(path,O_RDONLY);
if(-1 == fd)
{
printf("FileManager::SendFile open error\n");
return ;
}
struct stat info;
fstat(fd,&info);
printf("file %s size is %d\n",filename,info.st_size);
short total_size = 4;
total_size += sizeof(int);
total_size += strlen(filename);
short package_size = total_size - 2;
char* buf = (char*)malloc(total_size);
memcpy(buf,&package_size,2);
char type='F';
memcpy(buf+2,&type,1);
char extra = 0;
memcpy(buf+3,&extra,1);
int file_size = info.st_size;
memcpy(buf+4,&file_size,4);
memcpy(buf+8,filename,strlen(filename));
printf("total_size:%d\n",total_size);
socket_server_send(ss,conn_id,buf,total_size);
char buffer[2048]={0};
while(1)
{
lseek(fd,loc,SEEK_SET);
short size = read(fd,buffer,1024);
if(-1 == size)
{
printf("file_manager: file read error\n");
break;
}
else if(0 == size)
{
printf("file_manager: file send over!\n");
break;
}
printf("file send package size:%d\n",size);
loc += size;
total_size = size+4;
buf = (char*)malloc(total_size);
package_size = total_size-2;
memcpy(buf,&package_size,2);
memcpy(buf+2,&type,1);
extra = 1;
memcpy(buf+3,&extra,1);
memcpy(buf+4,buffer,size);
socket_server_send(ss,conn_id,buf,total_size);
}
close(fd);
}