1. 程式人生 > >【Linux C/C++】 第06講 檔案IO

【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);	
}