linux 文件I/O操作

目錄

一、linux系統文件和文件系統

1.1文件類型

1.2 system函數

1.3linux文件權限

1.4 設置系統文件、目錄初始默認權限

1.5文件其他屬性


一、linux系統文件和文件系統

003vPl7Rty6E8kZRlAEdc&690

 

  • /bin
    bin是Binary的縮寫, 這個目錄存放着最經常使用的命令。包括用戶管理員命令,如:cat,chmod,cp,date,ls

  • /boot:
    這裏存放的是啓動Linux時使用的一些核心文件,包括一些連接文件以及鏡像文件。

  • /dev :
    dev是Device(設備)的縮寫, 該目錄下存放的是Linux的外部設備,在Linux中訪問設備的方式和訪問文件的方式是相同的。

  • /etc:
    這個目錄用來存放所有的系統管理所需要的配置文件和子目錄。

  • /home
    用戶的主目錄,在Linux中,每個用戶都有一個自己的目錄,一般該目錄名是以用戶的賬號命名的。

  • /lib
    這個目錄裏存放着系統最基本的動態連接共享庫,其作用類似於Windows裏的DLL文件。幾乎所有的應用程序都需要用到這些共享庫。如:c/c++等庫文件 其他大部分文件存放在/usr/lib下

  • /lost+found
    這個目錄一般情況下是空的,當系統非法關機後,這裏就存放了一些文件

  • /media
    linux系統會自動識別一些設備,例如U盤、光驅等等,當識別後,linux會把識別的設備掛載到這個目錄下。雙系統windows下的磁盤和插入的u盤都會在'media/用戶名/' 目錄下   

  • /mnt
    系統提供該目錄是爲了讓用戶臨時掛載別的文件系統的,我們可以將光驅掛載在/mnt/上,然後進入該目錄就可以查看光驅裏的內容了。

  • /opt
     這是給主機額外安裝軟件所擺放的目錄。比如你安裝一個ORACLE數據庫則就可以放到這個目錄下。默認是空的。應用商店裏的好多軟件包括deepinwine都在這裏。(通過deepinwine安裝的windows軟件也在下面)

  • /proc
    這個目錄是一個虛擬的目錄,它是系統內存的映射,我們可以通過直接訪問這個目錄來獲取系統信息。
    這個目錄的內容不在硬盤上而是在內存裏,我們也可以直接修改裏面的某些文件,比如可以通過下面的命令來屏蔽主機的ping命令,使別人無法ping你的機器:

    echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
  • /root
    該目錄爲系統管理員,也稱作超級權限者的用戶主目錄。

  • /sbin
    s就是Super User的意思,這裏存放的是系統管理員使用的系統管理程序。

  • /selinux
     這個目錄是Redhat/CentOS所特有的目錄,Selinux是一個安全機制,類似於windows的防火牆,但是這套機制比較複雜,這個目錄就是存放selinux相關的文件的。

  • /srv
     該目錄存放一些服務啓動之後需要提取的數據。

  • /sys

     這是linux2.6內核的一個很大的變化。該目錄下安裝了2.6內核中新出現的一個文件系統 sysfs 。

    sysfs文件系統集成了下面3種文件系統的信息:針對進程信息的proc文件系統、針對設備的devfs文件系統以及針對僞終端的devpts文件系統。

     

    該文件系統是內核設備樹的一個直觀反映。

    當一個內核對象被創建的時候,對應的文件和目錄也在內核對象子系統中被創建。

  • /tmp
    這個目錄是用來存放一些臨時文件的。

  • /usr
     這是一個非常重要的目錄,用戶的很多應用程序和文件都放在這個目錄下,類似於windows下的program files目錄。

  • /usr/bin:
    系統用戶使用的應用程序。

  • /usr/sbin:
    超級用戶使用的比較高級的管理程序和系統守護程序。

  • /usr/src:
    內核源代碼默認的放置目錄。

  • /var
    這個目錄中存放着在不斷擴充着的東西,我們習慣將那些經常被修改的目錄放在這個目錄下。包括各種日誌文件。

  • /run
    是一個臨時文件系統,存儲系統啓動以來的信息。當系統重啓時,這個目錄下的文件應該被刪掉或清除。如果你的系統上有 /var/run 目錄,應該讓它指向 run。

 

在 Linux 系統中,有幾個目錄是比較重要的,平時需要注意不要誤刪除或者隨意更改內部文件。

/etc: 上邊也提到了,這個是系統中的配置文件,如果你更改了該目錄下的某個文件可能會導致系統不能啓動。

/bin, /sbin, /usr/bin, /usr/sbin: 這是系統預設的執行文件的放置目錄,比如 ls 就是在/bin/ls 目錄下的。

值得提出的是,/bin, /usr/bin 是給系統用戶使用的指令(除root外的通用戶)而/sbin, /usr/sbin 則是給root使用的指令

/var: 這是一個非常重要的目錄,系統上跑了很多程序,那麼每個程序都會有相應的日誌產生,而這些日誌就被記錄到這個目錄下,具體在/var/log 目錄下,另外mail的預設放置也是在這裏。

1.1文件類型

普通文件(-)
目錄文件(r)
符號鏈接文件(l)
字符設備文件(c)
塊設備文件(b)
管道文件(p)
socket文件(s)

1.2 system函數

頭文件:#include<stdlib.h>
函數功能:在進程中開始另一個進程
函數原型:int system(const char* string)
函數傳入值:系統變量 shell命令
函數返回值:執行成功返回執行shell命令後的返回值;調用/bin/sh失敗返回127;
                     其他原因失敗則返回-1,;參數string爲空(null),則返回非0值
備註:system()調用fork()產生子進程,子進程調用/bin/sh -c string來執行參數
          string字符串所代表的命令,此命令執行完畢後隨即返回原調用的進程。如果調用
          成功,返回shell命令後的返回值可能也是127(該shell命令就返回數字結果127),
          因此,最好能檢查error來確定執行情況。

eg1:列出當前目錄和系統目錄'/dev/sda1' '/dev/lp0'下的信息

#include<stdio.h>
#include<stdlib.h>
int main(){
	int newret;
	printf("列出當前目錄下的文件信息:\n");
	newret=system("ls -l");
	printf("列出'/dev/sda1'下的文件信息:\n");
	newret=system("ls /dev/sda1 -l");
	printf("列出'/dev/lp0'下的文件信息:\n");
	newret=system("ls /dev/lp0 -l");
	return 0;
}

運行結果:

eg2:編寫一個c程序,用system函數調用一個shell函數,完成某文件中某一個字符的查找

/*完成某文件中某一字符串的查找*/ 
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main(){
	char a[100],b[100],cmd[100];
	printf("請輸入文件名:\n");
	scanf("%s",a);
	printf("請輸入字串:\n");
	scanf("%s",b);
	strcpy(cmd,"./substr ");
	strcat(cmd,a);
	strcat(cmd," ");
	strcat(cmd,b);
	printf("執行命令:%s\n",cmd);
	system(cmd);
	return 0;
}

運行結果:

 

eg3:編寫c程序,用system函數調用另一個c程序

#include<stdio.h>
#include<stdlib.h>
int main(){
	system("./5-1-1");
	return 0;
}

運行結果:同eg2 就是調用eg2的c程序

 

1.3linux文件權限

四種權限:可讀r,可寫w,可執行x,無權限-

頭文件:#include<sys/types.h>
      #include<sys/stat.h>
函數功能:改變文件權限 (注意這是c語言函數 不是shell命令)
函數原型:int chmod(const char* path,mode_t mode)
函數傳入值:依參數mode的權限來更改參數path 指定文件的權限
函數返回值:權限改變成功返回0,失敗返回-1,錯誤返回errno

mode參數說明
參數 說明
S_IRUSR 所有者具有讀權限
S_IWUSR 所有者具有寫權限
S_IXUSR 所有者具有執行權限
S_IRGRP 組具有讀權限
S_IWGRP 組具有寫權限
S_IXGRP 組具有執行權限
S_IROTH 其他用戶具有讀權限
S_IWOTH 其他用戶具有寫權限
S_IXOTH 其他用戶具有執行權限

eg1:將~/test/a.txt文件的權限設置爲所有者可讀可寫,其他用戶只讀

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<stdlib.h>
int main(){
	printf("修改前 ~/test/a.txt 的權限:\n");
	system("ls -l ~/test/a.txt");
	chmod("/home/hanzhuan/test/a.txt",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
	printf("修改後 ~/test/a.txt 的權限:\n");
	system("ls -l ~/test/a.txt");
	return 0;
}

運行結果:

 

1.4 設置系統文件、目錄初始默認權限

所需頭文件:#include<sys/types.h>
                     #include<sys/stat.h>
函數功能:設置建立新文件時的權限掩碼(但是返回的是原來的權限掩碼)
函數原型:mode_t umask(mode_t mask);
函數傳入值:4位8進制數
函數返回值:原先系統的權限掩碼(umask值)
備註:建立文件時,該文件的真正權限爲(0666-mask)
           建立文件夾時,該文件夾的真正權限爲(0777-mask)
           值範圍爲0~7 開頭的0表示8進制 

eg1:設計一個程序,應用umask函數設置系統文件與目錄的權限掩碼.要求:新建文件的權限分別是0000和0222

/*設計一個程序,應用umask函數設置系統文件與目錄的權限掩碼*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
int main(){
	mode_t new_umask,old_mask;
	new_umask=0666;
	old_mask=umask(new_umask);//設置新權限掩碼爲0666(新文件權限爲0000 新文件夾權限爲0111) 返回舊權限
	printf("系統原來的權限掩碼是:%o\n",old_mask);
	printf("系統新的權限掩碼是:%o\n",new_umask);
	printf("系統新的文件權限是:%o\n",0666-new_umask);
	printf("系統新的文件夾權限是:%o\n",0777-new_umask);
	system("touch file1");
	system("mkdir dir1");
	printf("創建了文件file1\n");
	printf("創建了文件夾dir1\n");
	new_umask=0444;
	old_mask=umask(new_umask);//設置新權限掩碼爲0444(新文件權限爲0222 新文件夾權限爲0333)
	printf("系統原來的權限掩碼是:%o\n",old_mask);
	printf("系統新的權限掩碼是:%o\n",new_umask);
	printf("系統新的文件權限是:%o\n",0666-new_umask);
	printf("系統新的文件夾權限是:%o\n",0777-new_umask);
	system("touch file2");
	system("mkdir dir2");
	printf("創建了文件file2\n");
	printf("創建了文件夾dir2\n");
	system("ls file1 -l");
	system("ls -l | grep dir1");
	system("ls file2 -l");
	system("ls -l | grep dir2");
	chmod("file2",S_IWUSR|S_IXOTH);
	printf("強制改爲w-x:\n");
	system("ls file2 -l");
	return 0;
}

運行結果:

 

1.5文件其他屬性

強大的stat結構體

在使用這個結構體和方法時,需要引入:

<sys/types.h>

<sys/stat.h>

struct stat這個結構體是用來描述一個linux系統文件系統中的文件屬性的結構。

可以有兩種方法來獲取一個文件的屬性:

1、通過路徑:

int stat(const char *path, struct stat *struct_stat);

int lstat(const char *path,struct stat *struct_stat);

兩個函數的第一個參數都是文件的路徑,第二個參數是struct stat的指針。返回值爲0,表示成功執行。

執行失敗是,error被自動設置爲下面的值:

EBADF: 文件描述詞無效

EFAULT: 地址空間不可訪問

ELOOP: 遍歷路徑時遇到太多的符號連接

ENAMETOOLONG:文件路徑名太長

ENOENT:路徑名的部分組件不存在,或路徑名是空字串

ENOMEM:內存不足

ENOTDIR:路徑名的部分組件不是目錄

這兩個方法區別在於stat沒有處理字符鏈接(軟鏈接)的能力,如果一個文件是符號鏈接,stat會直接返回它所指向的文件的屬性;而lstat返回的就是這個符號鏈接的內容。這裏需要說明一下的是軟鏈接和硬鏈接的含義。我們知道目錄在linux中也是一個文件,文件的內容就是這這個目錄下面所有文件與inode的對應關係。那麼所謂的硬鏈接就是在某一個目錄下面將一個文件名與一個inode關聯起來,其實就是添加一條記錄!而軟鏈接也叫符號鏈接更加簡單了,這個文件的內容就是一個字符串,這個字符串就是它所鏈接的文件的絕對或者相對地址。

2、通過文件描述符

int fstat(int fdp, struct stat *struct_stat);  //通過文件描述符獲取文件對應的屬性。fdp爲文件描述符

下面是這個結構的結構

struct stat {
        mode_t     st_mode;       //文件對應的模式,文件,目錄等
        ino_t      st_ino;       //inode節點號
        dev_t      st_dev;        //設備號碼
        dev_t      st_rdev;       //特殊設備號碼
        nlink_t    st_nlink;      //文件的連接數
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者對應的組
        off_t      st_size;       //普通文件,對應的文件字節數
        time_t     st_atime;      //文件最後被訪問的時間
        time_t     st_mtime;      //文件內容最後被修改的時間
        time_t     st_ctime;      //文件狀態改變時間
        blksize_t st_blksize;    //文件內容對應的塊大小
        blkcnt_t   st_blocks;     //偉建內容對應的塊數量
      };

stat結構體中的st_mode 則定義了下列數種情況:

    S_IFMT   0170000    文件類型的位遮罩
    S_IFSOCK 0140000    scoket
    S_IFLNK 0120000     符號連接
    S_IFREG 0100000     一般文件
    S_IFBLK 0060000     區塊裝置
    S_IFDIR 0040000     目錄
    S_IFCHR 0020000     字符裝置
    S_IFIFO 0010000     先進先出

    S_ISUID 04000     文件的(set user-id on execution)位
    S_ISGID 02000     文件的(set group-id on execution)位
    S_ISVTX 01000     文件的sticky位

    S_IRUSR(S_IREAD) 00400     文件所有者具可讀取權限
    S_IWUSR(S_IWRITE)00200     文件所有者具可寫入權限
    S_IXUSR(S_IEXEC) 00100     文件所有者具可執行權限

    S_IRGRP 00040             用戶組具可讀取權限
    S_IWGRP 00020             用戶組具可寫入權限
    S_IXGRP 00010             用戶組具可執行權限

    S_IROTH 00004             其他用戶具可讀取權限
    S_IWOTH 00002             其他用戶具可寫入權限
    S_IXOTH 00001             其他用戶具可執行權限

    上述的文件類型在POSIX中定義了檢查這些類型的宏定義:

    S_ISLNK (st_mode)    判斷是否爲符號連接
    S_ISREG (st_mode)    是否爲一般文件
    S_ISDIR (st_mode)    是否爲目錄
    S_ISCHR (st_mode)    是否爲字符裝置文件
    S_ISBLK (s3e)        是否爲先進先出
    S_ISSOCK (st_mode)   是否爲socket

 

eg1:編寫程序實現輸出指定文件的大小、最後一次訪問時間和最後一次修改時間

/*獲取文件大小 最後一次訪問時間 最後一次修改時間*/
#include<stdio.h>
#include<time.h>
#include <unistd.h>
#include<sys/stat.h>
int main(){
	struct stat buf;
	char a[100];
	struct tm *p1,*p2;
	printf("輸入文件完整路徑+文件名:");
	scanf("%s",a);
	stat(a,&buf);
	p1=localtime(&buf.st_atime);//獲取當地時間 並按現在的時間日期來表示
	p2=localtime(&buf.st_mtime);//struct tm *p=localtime(&time_t); tm強大結構體 
	printf("文件名:%s\n",a);
	printf("大 小:%d\n",buf.st_size);
	printf("最後一次訪問時間: %d年%d月%d日 %d:%d:%02d\n",1900+p1->tm_year,p1->tm_mon+1,p1->tm_mday,p1->tm_hour,p1->tm_min,p1->tm_sec);
	printf("最後一次修改時間: %d年%d月%d日 %d:%d:%02d\n",1900+p2->tm_year,p2->tm_mon+1,p2->tm_mday,p2->tm_hour,p2->tm_min,p2->tm_sec);
	return 0;
}

運行結果:

 

二、不帶緩存的文件I/O操作

不帶緩存的文件I/O操作用到的主要API函數
函數 作用
creat 創建文件
open 打開或創建文件
close 關閉文件
read 讀文件
write 寫文件
lseek 移動文件的讀寫位置
flock 鎖定文件或解除鎖定(用於文件加建議性鎖)
fcntl 文件描述符操作(用於文件加強制性鎖)

2.1文件的創建

所需頭文件:#include<sys/types.h>
                      #include<sys/stat.h>
                      #include<fcntl.h>
函數功能:創建文件
函數原型:int creat(const char* pathname,mode_t mode);
函數傳入值:建立文件的訪問路徑,用來設置新增文件的權限
                     參數mode見1.3linux文件權限
函數返回值:由內核返回一個最小可用的文件描述符,出錯返回-1
 

eg1:編程實現在~/test/Io/目錄下創建一個名爲io.txt的文件,並將此文件的權限設置爲所有者具有隻讀權限,最後顯示此文件的信息。

/*c程序創建文件 並指定權限*/
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
int main(){
	int fd;
	fd=creat("/home/hanzhuan/test/IO/io.txt",S_IRUSR);
	system("ls /home/hanzhuan/test/IO/io.txt -l");
	return 0;
}

運行結果:

 

2.2 文件的打開和關閉

open函數說明:

所需頭文件:#include<sys/types.h>
                      #include<sys/stat.h>
                      #include<fcntl.h>
函數功能:打開文件(不存在創建文件)
函數原型:int open(const char * pathname,int flags);
                  int open(const char * pathname,int flags,mode_t mode);
函數傳入值:建立文件的訪問路徑,用來設置新增文件的權限
                     建立文件的訪問路徑,指定訪問文件的命令模式,用來設置新增文件的權限
函數返回值:由內核返回一個最小可用的文件描述符,出錯返回-1

flag參數說明如下:
O_RDONLY:以只讀模式打開
O_WRONLY:以寫入模式打開
O_RDWR:以讀寫模式打開
O_APPEND:在文件尾寫入數據
O_TRUNC:設置文件的長度0,並捨棄現存的數據
O_CREAT:建立文件,可用mode參數設置訪問權限
O_EXCL:與O_CREAT一起使用,若所建立的文件已存在,則打開失敗

close函數說明如下:
所需頭文件:#include<unistd.h>
函數功能:關閉文件
函數原型:int close(int fd);
函數傳入值:整型
函數返回值:文件順利關閉返回0,發生錯誤返回-1
備註:當一個進程終止時,它所有已打開的文件都由內核自動關閉
         雖然如此,但:還是建議人工關閉文件,並檢查返回值

 

 

 

eg:在/home/hanzhuan/test/IO目錄下以可讀寫方式打開一個文件,若不存在創建此文件;若存在,清空後關閉

(原來目錄下有io1.txt且有內容 無io2.txt)

/*打開文件*/
#include<stdio.h>
#include<stdlib.h>/*system*/
#include<fcntl.h>/*open*/
#include<unistd.h>/*close*/
int main(){
	int fd;
	if((fd=open("/home/hanzhuan/test/IO/io1.txt",O_CREAT|O_TRUNC|O_WRONLY,0600))<0){
		/*O_CREAT:b不存在建立文件 
		  O_TRUNC:設置文件的長度0,並捨棄現存的數據
		  O_WRONLY:以寫入模式打開
		  0600:所有者rw權限
		  出錯返回-1<0		  
		*/
		perror("打開文件出錯!");
		exit(1);
	}else{
		printf("打開(創建)文件 io1.txt ,文件描述符爲:%d\n",fd);
	}
	if(close(fd)<0){
		perror("關閉文件出錯!");
		exit(1);
	}
	system("ls /home/hanzhuan/test/IO/io1.txt -l");
	return 0;
}

運行結果:

 

2.3 文件的讀寫操作

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章