目錄
一、linux系統文件和文件系統
/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
參數 | 說明 |
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操作
函數 | 作用 |
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 文件的讀寫操作