1. 程式人生 > 其它 >Linux程式設計入門(3)-檔案讀寫操作(cp指令實現)

Linux程式設計入門(3)-檔案讀寫操作(cp指令實現)

學習目標

通過分析 cp 指令,來學習 Linux 程式設計讀寫檔案操作。

程式碼實驗環境

作業系統:Ubuntu 18.04 LTS

編譯器gcc版本:gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

cp指令介紹

cp 指令主要用於複製檔案或者目錄。

典型用法:

cp [options] source dest

詳細的選項引數說明可以查閱相關資料。此處只介紹 cp 指令複製檔案的功能。

如果目標檔案 dest 不存在,則 cp 會建立這個檔案。如果存在,則用 source 檔案的內容覆蓋 dest 檔案。

cp如何複製檔案

實現 cp 指令的複製檔案功能有兩個關鍵點:首先,需要能夠建立一個新檔案或者清空已有檔案。其次,能夠把原檔案的內容寫入到目標檔案中。

  1. 建立檔案

Linux 有一個系統函式 creat() 既能新建立一個檔案,也能清空已有檔案。其函式原型如下:

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

int creat(const char *pathname, mode_t mode);

引數 pathname,為檔名

引數 mode,檔案訪問模式。模式定義如下,

S_IRWXU  00700 檔案所有者擁有讀、寫、執行許可權
S_IRUSR  00400 檔案所有者擁有讀許可權
S_IWUSR  00200 檔案所有者擁有寫許可權
S_IXUSR  00100 檔案所有者擁有執行許可權
S_IRWXG  00070 同組使用者擁有讀、寫、執行許可權
S_IRGRP  00040 同組使用者擁有讀許可權
S_IWGRP  00020 同組使用者擁有寫許可權
S_IXGRP  00010 同組使用者擁有執行許可權
S_IRWXO  00007 其他使用者擁有讀、寫、執行許可權
S_IROTH  00004 其他使用者擁有讀許可權
S_IWOTH  00002 其他使用者擁有寫許可權
S_IXOTH  00001 其他使用者擁有執行許可權

此函式等效於,利用 open 函式實現建立新檔案或者清空已有檔案,並開啟此檔案:

open(const char * pathname, (O_CREAT | O_WRONLY | O_TRUNC), mode_t mode);

creat() 函式告訴核心建立一個名字為 pathname 的檔案,如果不存在,就建立它;如果存在就把它的內容清空,檔案長度設定為 0。

建立成功,會返回一個指向此檔案的檔案描述符。建立失敗,則返回 -1 。

檔案建立成功後,檔案的訪問許可位,被設定為 mode 引數的值。

  1. 寫檔案

寫檔案系統呼叫函式為 write(),函式原型如下

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

引數 fd,為檔案描述符。

引數 buf,儲存寫入資料的記憶體指標(地址)。

引數 count,為要寫入資料的位元組個數。

這個系統呼叫函式告訴核心將記憶體中指定的資料寫入檔案。如果核心不能寫入或者寫入失敗,wirte 返回 -1。如果寫入成功,則返回實際寫入的位元組數。

有時候會出現,寫入的位元組數少於要求的數目。原因有二:(1)有的系統對檔案的最大尺寸有限制;(2)磁碟空間接近滿了。

核心會盡量把資料寫入檔案,並將實際寫入的位元組數返回。

編寫 cp 程式碼

程式的執行流程:

編寫程式程式碼 cp1.c :

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

/* 定義緩衝區大小的巨集 */
#define BUFFSIZE    4096
/* 檔案訪問模式,檔案所有者擁有讀寫許可權,同組使用者擁有讀許可權,其他使用者擁有讀許可權 */
#define COPYMODE    0644

/* 錯誤資訊顯示函式 */
void oops(char *s1, char *s2);

int main(int ac, char *av[])
{
	int in_fd, out_fd, n_chars;
	char buf[BUFFSIZE];

	/* 判斷引數個數 */
	if(ac != 3)
	{
		fprintf(stderr, "usage: %s source destination\n", *av);
		exit(1);
	}

	/* 開啟原檔案 */
	if((in_fd = open(av[1], O_RDONLY)) == -1)
	{
		oops("Cannot open ", av[1]);
	}

	/* 建立目標檔案 */
	if((out_fd = creat(av[2], COPYMODE)) == -1)
	{
		oops("Cannot creat ", av[2]);
	}

	/* 讀原檔案內容,並判斷讀取的位元組數是否大於 0 */
	while((n_chars = read(in_fd, buf, BUFFSIZE)) > 0)
	{
		/* 將讀取的資料寫入檔案 */
		if(write(out_fd, buf, n_chars) != n_chars)
		{
			oops("Write error to ", av[2]);
		}
	}

	/* 如果讀檔案出錯,給出錯誤資訊 */
	if(n_chars == -1)
	{
		oops("Read error from ", av[1]);
	}

	/* 關閉原檔案和目標檔案 */
	if((close(in_fd) == -1) || (close(out_fd) == -1))
	{
		oops("Error closing files", "");
	}
}

/* 錯誤資訊輸出 */
void oops(char *s1, char *s2)
{
	fprintf(stderr, "Error: %s", s1);
	perror(s2);
	exit(1);
}

編譯,並測試以上程式碼:

$ gcc cp1.c -o cp1

$ ./cp1 test test_cp1

$ ls test test_cp1 -l
-rwxrwxr-x 1 user user 8728 11月  3 00:10 test
-rw-r--r-- 1 user user 8728 11月  3 00:12 test_cp1

可以看到我們編寫的程式能正常執行,可以完成檔案的複製工作。原檔案和目標檔案的大小和內容相同。

看看程式對錯誤輸入的反應

$ ./cp1 tes test_cp1
Error: Cannot open tes: No such file or directory

$ ./cp1 test
usage: ./cp1 source destination

$ ./cp1 test /tmp
Error: Cannot creat /tmp: Is a directory

總結

通過分析 cp 指令的原理,完成 cp 複製檔案的功能程式碼,學習了 Linux 程式設計實現對檔案的讀寫操作。

涉及到的系統函式:

  • open 開啟一個檔案
  • creat 建立一個檔案
  • read 讀取檔案內容
  • write 向檔案寫入資料
  • close 關閉開啟的檔案

關注公眾號【一起學嵌入式】,獲取更多技術乾貨。