嵌入式Linux—檔案IO

2023-02-11 06:01:06

檔案IO

在 Linux 系統中,一切都是「 檔案」:普通檔案、驅動程式、網路通訊等等。所有的操作,都是通過「檔案 IO」來進行的。所以,很有必要掌握檔案操作的常用介面。

Linux系統的檔案有哪些

Linux 的檔案既可以是真實儲存到儲存媒介的檔案也可以是自身核心提供的虛擬檔案,還可以是裝置節點 。

存取檔案的方式
型別 方法
通用的 IO 模型: open/read/write/lseek/close
非通用的函數 ioctl/mmap
Linux下的幫助方法
方法 功能
xxx --help 單個命令的用法
man 分類號 xxx 用法與函數詳細介紹(最常用)
info 更加詳細的內容(不常用)

man的9大分類:

1 Executable programs or shell commands // 命令
2 System calls (functions provided by the kernel) // 系統呼叫,比如 man 2 open
3 Library calls (functions within program libraries) // 函數庫呼叫
4 Special files (usually found in /dev) // 特殊檔案, 比如 man 4 tty
5 File formats and conventions eg /etc/passwd // 檔案格式和約定, 比如 man 5 passwd
6 Games // 遊戲
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) //雜項
8 System administration commands (usually only for root) // 系統管理命令
9 Kernel routines [Non standard] // 核心例程
系統呼叫怎麼進入核心以及核心的 sys_open、 sys_read 會做什麼

詳見《完全開發手冊》P171-P172

檔案IO的常用函數(可通過man方法獲取更多細節)
函數 功能
int open(const char *pathname, int flags, mode_t mode); 建立一條到檔案或裝置的存取路徑,返回檔案描述符。mode引數只有使用 O_CREAT 標誌建立一個新檔案時才有效。
ssize_t read(int fd, void *buf, size_t count); 通過檔案描述符讀位元組到緩衝區(實體記憶體),並返回位元組數,若檔案為空,則返回-1
ssize_t write(int fd, const void *buf, size_t count); 通過檔案描述符,從buf開始寫count個位元組到檔案
int fstat(int fd, struct stat *statbuf); 返回檔案的狀態資訊到statbuf結構體,通過結構體儲存檔案狀態
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 將磁碟檔案對映到記憶體(虛擬記憶體),實際上會返回記憶體對映的起始地址

標準IO方式:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

/**
 * argv[1]:新檔案
 * argv[2]:舊檔案
 **/
int main(int argc, char **argv)
{
	int fd_old, fd_new;
	char data[1024];   //1024個位元組為一組
	int len;
	/*格式提醒*/
	if(argc != 3) {
		printf("Usage: %s <old-file> <new-file>\n", argv[0]);
		return -1;
	}
	/* 1.開啟檔案 */
	fd_old = open(argv[2], O_RDONLY);
	if(fd_old == -1) {
		printf("can not open file %s\n", argv[2]);  //開啟檔案失敗
		return -1;
	}
	/* 2.建立新檔案 */
	fd_new = open(argv[1], O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
	if(fd_new == -1) {
		printf("can not creat file %s\n", argv[1]);
		return -1;
	}
	/* 3.讀取舊檔案,寫入新檔案 */
	while((len = read(fd_old, data, 1024)) > 0) {
		if(write(fd_new, data, len) != len) {
			printf("can not wite file %s\n", argv[2]);
			return -1;
		}
	}
	/* 4.關閉檔案 */
	close(fd_old);
	close(fd_new);

	return 0;
}

非通用IO(mmap):


    #include <sys/stat.h>
   	#include <fcntl.h>
	#include <sys/types.h>
 	#include <stdio.h>
    #include <unistd.h>
 	#include <sys/mman.h>

int main(int argc, char **argv) {
	int fd_old, fd_new;
	struct stat stat;
	char *ptr;  //記憶體對映的起始地址
	/* 1.判斷指令 */
	if(argc != 3) {
		printf("Usage: %s <new-file> <old-file>\n", argv[0]);
		return -1;
	}

	/* 2.開啟舊檔案 */
	fd_old = open(argv[2], O_RDONLY);
	if(fd_old == -1) {
		printf("can not open %s\n", argv[2]);
		return -1;
	}

	/* 3.獲取檔案長度 */
	if(fstat(fd_old, &stat) == -1) {   //獲取檔案資訊
		printf("can not get stat of %s\n", argv[2]);
		return -1;
	}

	/* 4.對映舊檔案 */
	ptr = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd_old, 0);
	if(ptr == MAP_FAILED) {
		printf("can not mmap file %s\n", argv[2]);
		return -1;
	}

	/* 5.建立新檔案 */
	fd_new = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
	if(fd_new == -1) {
		printf("can not creat file %s\n", argv[2]);
		return -1;
	}

	/* 6.寫新檔案 */
	if(write(fd_new, ptr, stat.st_size) != stat.st_size) {
		printf("can not write %s\n", argv[1]);
		return -1;
	}

	/* 7.關閉檔案 */
	close(fd_new);
	close(fd_old);
	
	return 0;
}