2015Linux操作系統下C語言編程入門_第1頁
2015Linux操作系統下C語言編程入門_第2頁
2015Linux操作系統下C語言編程入門_第3頁
2015Linux操作系統下C語言編程入門_第4頁
已閱讀5頁,還剩87頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

linux操作系統下c語言編程入門(―■)目錄介紹Linux程序設計入門一基礎知識Linux程序設計入門ー進程介紹Linux程序設計入門一文件操作Linux程序設計入門一時間概念Linux程序設計入門一信號處理Linux程序設計入門一消息管理Linux程序設計入門ー線程操作Linux程序設計入門ー網絡編程Linux下C開發工具介紹(二)具體內容1)Linux程序設計入門一基礎知識Linux下C語言編程基礎知識前言:這篇文章介紹在LINUX下進行C語言編程所需要的基礎知識.在這篇文章當中,我們將會學到以下內容:源程序編譯Makefile的編寫程序庫的鏈接程序的調試頭文件和系統求助.源程序的編譯在Linux下面,如果要編譯ー個C語言源程序,我們要使用GNU的gcc編譯器.下面我們以ー個實例來說明如何使用gcc編譯器.假設我們有下面一個非常簡單的源程序(hello,c):intmain(intargc,char**argv){printf("HelloLinux\n");)要編譯這個程序,我們只要在命令行下執行:gcc-ohellohello,cgcc編譯器就會為我們生成一個hello的可執行文件.執行./hell。就可以看到程序的輸出結果了.命令行中gcc表示我們是用gcc來編譯我們的源程序,ー〇選項表示我們要求編譯器給我們輸出的可執行文件名為hello而hello,c是我們的源程序文件.gcc編譯器有許多選項,?■?般來說我們只要知道其中的幾個就夠了.ー〇選項我們已經知道了,表示我們要求輸出的可執行文件名.-c選項表示我們只要求編譯器輸出目標代碼,而不必要輸出可執行文件.飛選項表示我們要求編譯器在編譯的時候提供我們以后對程序進行調試的信息.知道了這三個選項,我們就可以編譯我們自己所寫的簡單的源程序了,如果你想要知道更多的選項,可以査看gcc的幫助文檔,那里有著許多對其它選項的詳細說明..Makefile的編寫假設我們有ド面這樣的ー個程序,源代碼如ド:main,c#include“mytooll.h"ttinclude〃mytool2?h”intmain(intargc,char**argv)imytooll_print("hello);mytool2_print("hello");)/*mytooll.h*/ttifndef_MYTOOL_1_H^define_MYT00L」_Hvoidmytooll_print(char*print_str);#endif/*mytooll.c*/#include"mytool1.h"voidmytooll_print(char*print_str){printf("Thisismytoollprint%s\n",print_str);}/*mytool2.h*/ttifndef_MYT00L_2_Httdefine_MYTOOL_2_Hvoidmytool2_print(char*print_str);#endif/*mytool2.c*/^include"mytool2.h"voidmytool2_print(char*print_str)printf("Thisismytool2print%s\n",print_str);當然由于這個程序是很短的我們可以這樣來編譯gcc-cmain,cgcc-cmytooll.cgcc-cmytool2.cgcc-omainmain,omytooll.omytool2.〇這樣的話我們也可以產生main程序,而且也不時很麻煩.但是如果我們考慮一下如果有一天我們修改了其中的一個文件(比如說mytooll.c)那么我們難道還要重新輸入上面的命令?也許你會說,這個很容易解決啊,我寫ー個SHELL腳本,讓她幫我去完成不就可以了.是的對于這個程序來說,是可以起到作用的.但是當我們把事情想的更復雜一點,如果我們的程序有幾百個源程序的時候,難道也要編譯器重新一個ー個的去編譯?為此,聰明的程序員們想出了一個很好的工具來做這件事情,這就是make.我們只要執行一下make,就可以把上面的問題解決掉.在我們執行make之前,我們要先編寫ー個非常重要的文件.一Makefile.對于上面的那個程序來說,可能的ー個Makefile的文件是:#這是上面那個程序的Makefile文件main:main.〇mytooll.〇mytool2.〇gcc-〇mainmain.〇mytooll.〇mytool2.〇main.o:main.cmytooll.hmytool2.hgcc-cmain,cmytooll.o:mytooll.cmytooll.hgcc-cmytooll.cmytool2.o:mytool2.cmytool2.hgcc-cmytool2.c有了這個Makefile文件,不過我們什么時候修改了源程序當中的什么文件,我們只要執行make命令,我們的編譯器都只會去編譯和我們修改的文件有關的文件,其它的文件她連理都不想去理的.下面我們學習Makefile是如何編寫的,在Makefile中#開始的行都是注釋行.Makefile中最重要的是描述文件的依賴關系的說明.?般的格式是:target:componentsTABrule第一行表示的是依賴關系.第二行是規則,比如說我們上面的那個Makefile文件的第二行main:main.〇mytooll.〇mytool2.〇表示我們的目標(target)main的依賴對象(components)是main.〇mytooll.〇mytool2.〇當倚賴的對象在目標修改后修改的話,就要去執行規則一行所指定的命令.就象我們的上面那個Makefile第三行所說的ー樣要執行gcc-〇mainmain.〇mytooll.〇mytool2.〇注意規則ー行中的TAB表示那里是ー個TAB鍵Makefile有三個非常有用的變量.分別是$@,$ゝ$く代表的意義分別是:$?■ー目標文件,$へー-所有的依賴文件,$く一第?個依賴文件.如果我們使用上面三個變量,那么我們可以簡化我們的Makefile文件為:#這是簡化后的Makefilemain:main.〇mytooll.〇mytool2.〇gccー〇$@$main.o:main.cmytooll.hmytool2.hgcc-c$<mytooll.o:mytooll.cmytooll.hgcc"c$<mytool2.o:mytool2.cmytool2.hgcc-c$<經過簡化后我們的Makefile是簡單了一點,不過人們有時候還想簡單一點?這里我們學習ー個Makefile的缺省規則..c,〇:gcc-c$<這個規則表示所有的.〇文件都是依賴于相應的.c文件的.例如mytool.〇依賴于mytool.c這樣Makefile還可以變為:#這是再ー次簡化后的Makefilemain:main.〇mytooll.〇mytool2.〇gccー〇$@$..c.〇:gcc-c$<好了,我們的Makefile也差不多了,如果想知道更多的關于Makefile規則可以查看相應的文檔..程序庫的鏈接試著編譯下面這個程序/*temp,c*/#include<math.h>intmain(intargc,char**argv)Idoublevalue;printf("Value:%f\n”,value);}這個程序相當簡單,但是當我們用gcc-otemptemp.c編譯時會出現下面所示的錯誤./tmp/cc33Kydu.〇:Infunctionmain:/tmp/cc33Kydu.o(.text+Oxe):undefinedreferencetolog'collect2:Idreturned1exitstatus出現這個錯誤是因為編譯器找不到log的具體實現.雖然我們包括了正確的頭文件,但是我們在編譯的時候還是要連接確定的庫.在Linux下,為了使用數學函數,我們必須和數學庫連接,為此我們要加入ー1m選項,gcc-0temptemp,cTm這樣才能夠正確的編譯.也許有人要問,前面我們用printf函數的時候怎么沒有連接庫呢?是這樣的,對于ー些常用的函數的實現,gcc編譯器會自動去連接ー些常用庫,這樣我們就沒有必要自己去指定了.有時候我們在編譯程序的時候還要指定庫的路徑,這個時候我們要用到編譯器的ーL選項指定路徑.比如說我們有一個庫在/home/hoyt/mylib下,這樣我們編譯的時候還要加上?L/home/hoyt/mylib.對于ー些標準庫來說,我們沒有必要指出路徑.只要它們在其缺省庫的路徑下就可以了.系統的缺省庫的路徑/lib/usr/lib/usr/local/lib在這三個路徑下面的庫,我們可以不指定路徑.還有一個問題,有時候我們使用了某個函數,但是我們不知道庫的名字,這個時候怎么辦呢?很抱歉,對于這個問題我也不知道答案,我只有一個傻辦法.首先,我到標準庫路徑下面去找看看有沒有和我用的函數相關的庫,我就這樣找到了線程(thread)函數的庫文件(1ibpthread,a).當然,如果找不到,只有一個笨方法.比如我要找sin這個函數所在的庫.就只好用nmー〇/lib/*,soIgrepsin>;?/sin命令,然后看、/sin文件,到那里面去找了.在sin文件當中,我會找到這樣的一行libm-2.1.2.so:00009faOWsin這樣我就知道了sin在1通!11-2.1.2"〇庫里面,我用Tm選項就可以了(去掉前面的lib和后面的版本標志,就剩下m了所以是Tm).如果你知道怎么找,請趕快告訴我,我回非常感激的.謝謝!.程序的調試我們編寫的程序不太可能一次性就會成功的,在我們的程序當中,會出現許許多多我們想不到的錯誤,這個時候我們就要對我們的程序進行調試了.最常用的調試軟件是gdb.如果你想在圖形界面下調試程序,那么你現在可以選擇xxgdb.記得要在編譯的時候加入-g選項.關于gdb的使用可以看gdb的幫助文件.由于我沒有用過這個軟件,所以我也不能夠說出如何使用.不過我不喜歡用gdb.跟蹤ー個程序是很煩的事情,我一般用在程序當中輸出中間變量的值來調試程序的.當然你可以選擇自己的辦法,沒有必要去學別人的.現在有了許多IDE環境,里面已經自己帶了調試器了.你可以選擇幾個試一試找出自己喜歡的ー個用..頭文件和系統求助有時候我們只知道一個函數的大概形式,不記得確切的表達式,或者是不記得這函數在那個頭文件進行了說明.這個時候我們可以求助系統.比如說我們想知道fread這個函數的確切形式,我們只要執行manfread系統就會輸出這函數的詳細解釋的.和這個函數所在的頭文件〈stdio.h>說明了.如果我們要write這個函數的說明,當我們執行manwrite時,輸出的結果卻不是我們所需要的.因為我們要的是write這個函數的說明,可是出來的卻是write這個命令的說明.為了得到write的函數說明我們要用man2write.2表示我們用的write這個函數是系統調用函數,還有一個我們常用的是3表示函數是C的庫函數.記住不管什么時候,man都是我們的最好助手.好了,這一章就講這么多了,有了這些知識我們就可以進入激動人心的Linux下的C程序探險活動.2)Linux程序設計入門ー進程介紹Linux下進程的創建前言:這篇文章是用來介紹在Linux下和進程相關的各個概念.我們將會學到:進程的概念進程的身份進程的創建守護進程的創建1.進程的概念Linux操作系統是面向多用戶的.在同一時間可以有許多用戶向操作系統發出各種命令.那么操作系統是怎么實現多用戶的環境呢?在現代的操作系統里面,都有程序和進程的概念.那么什么是程序,什么是進程呢?通俗的講程序是ー個包含可以執行代碼的文件,是ー個靜態的文件.而進程是ー個開始執行但是還沒有結束的程序的實例.就是可執行文件的具體實現.ー個程序可能有許多進程,而每?個進程又可以有許多子進程.依次循環下去,而產生子孫進程.當程序被系統調用到內存以后,系統會給程序分配一定的資源(內存,設備等等)然后進行系列的変雜操作,使程序變成進程以供系統調用.在系統里面只有進程沒有程序,為了區分各個不同的進程,系統給每ー個進程分配了一個ID(就象我們的身份證)以便識別.為了充分的利用資源,系統還對進程區分了不同的狀態.將進程分為新建,運行,阻塞,就緒和完成五個狀態.新建表示進程正在被創建,運行是進程正在運行,阻塞是進程正在等待某ー個事件發生,就緒是表示系統正在等待CPU來執行命令,而完成表示進程已經結束了系統正在回收資源.關于進程五個狀態的詳細解說我們可以看《操作系統》上面有詳細的解說。2?進程的標志上面我們知道了進程都有一個ID,那么我們怎么得到進程的ID呢?系統調用getpid可以得到進程的ID,而getppid可以得到父進程(創建調用該函數進程的進程)的ID.tfinclude<unistd>pidtgetpid(void);pidtgetppid(void);進程是為程序服務的,而程序是為了用戶服務的.系統為了找到進程的用戶名,還為進程和用戶建立聯系.這個用戶稱為進程的所有者.相應的每ー個用戶也有一個用戶ID,通過系統調用getuid可以得到進程的所有者的ID.由于進程要用到ー些資源,而Linux對系統資源是進行保護的,為了獲取一定資源進程還有一個有效用戶ID.這個ID和系統的資源使用有關,涉及到進程的權限.通過系統調用geteuid我們可以得到進程的有效用戶ID.和用戶ID相對應進程還有一個組ID和有效組!D系統調用getgid和getegid可以分別得到組ID和有效組!D^include<unistd>#include<sys/types.h>uidtgetuid(void);uid_tgeteuid(void);gid_tgetgid(void);gittgetegid(void);有時候我們還會對用戶的其他信息感興趣(登錄名等等),這個時候我們可以調用getpwuid來得到.structpasswd{char*pw_name;/?登錄名稱?/char*pw_passwd;/?登錄ロ令?/uid_tpwuid;/*用戶ID*/gid_tpw_gid;/?用戶組ID*/char*pwgecos;/?用戶的真名?/char*pw_dir;/?用戶的目錄?/char*pw_shell;/?用戶的SHELL*/);#include<pwd.h>#include<sys/types.h>structpasswd*getpwuid(uid_tuid);下面我們學習ー個實例來實踐一下上面我們所學習的幾個函數:ftinclude<unistd.h>#include<pwd.h>#include<sys/types.h>ftinclude<stdio.h>intmain(intargc,char**argv)(pid_tmy_pid,parent_pid;uid_tmy_uid,my_euid;gid_tmy_gid,my_egid;structpasswd*my_info;my_pid=getpid();parent_pid=getppid();my_uid=getuid();my_euid=geteuid();my_gid=getgid();myegid=getegid();my_info=getpwuid(my_uid);printf("ProcessID:%ld\n",my_pid);printf("ParentID:%ld\n",parentpid);printf(*UserID:%ld\n",my_uid);printf("EffectiveUserID:%ld\n",my_euid);printf("GroupID:%ld\n",my_gid);printf(""EffectiveGroupID:%ld\n”,myegid):if(my_info)printf(z,MyLoginName:%s\nz/,my_info->pw_name);printf(zzMyPassword:%s\nzz,my_info->pw_passwd);printf(zzMyUserID:%ld\n”,my_info->pw_uid);printf(zzMyGroupID:%ld\nzz,my_info->pw_gid);printf(zzMyRealName:%s\nzz,my_info->pw_gecos);printf(z,MyHomeDir:%s\n",my__info->pw_dir);printf(zzMyWorkShell:%s\n*,my_info->pw_shell);3。進程的創建創建一個進程的系統調用很簡單,我們只要調用fork函數就可以了.#include<unistd.h>pidtfork();當ー個進程調用了fork以后,系統會創建一個子進程.這個子進程和父進程不同的地方只有他的進程ID和父進程ID,其他的都是ー樣.就象父進程克隆(clone)自己一樣.當然創建兩個ー模ー樣的進程是沒有意義的為了區分父進程和子進程,我們必須跟蹤fork的返回值,當fork掉用失敗的時候(內存不足或者是用戶的最大進程數已到)fork返回ー1,否則fork的返回值有重要的作用.對于父進程fork返回子進程的ID,而對于fork子進程返回0.我們就是根據這個返回值來區分父子進程的.父進程為什么要創建子進程呢?前面我們已經說過了Linux是ー個多用戶操作系統,在同一時間會有許多的用戶在爭奪系統的資源.有時進程為了早一點完成任務就創建子進程來爭奪資源.一旦子進程被創建,父子進程一起從fork處繼續執行,相互競爭系統的資源.有時候我們希望子進程繼續執行,而父進程阻塞直到子進程完成任務.這個時候我們可以調用wait或者waitpid系統調用.#include<sys/types.h>#include<sys/wait.h>pid_twait(int*stat_loc);pidtwaitpid(pid_tpid,int*stat_loc,intoptions);wait系統調用會使父進程阻塞直到ー個子進程結束或者是父進程接受到了一個信號.如果沒有父進程沒有子進程或者他的子進程已經結束wait回立即返回.成功時(因ー個子進程結束)wait將返回子進程的ID,否則返回一1,并設置全局變量errno.stat.loc是子進程的退出狀態,子進程調用exit,_exit或者是return來設置這個值.為了得到這個值Linux定義了幾個宏來測試這個返回值.WIFEXITED:判斷子進程退出值是非〇WEXITSTATUS:判斷子進程的退出值(當子進程退出時非0).WIFSIGNALED:子進程由于有沒有獲得的信號而退出.WTERMSIG:子進程沒有獲得的信號(在WIFSIGNALED為真時オ有意義).waitpid等待指定的子進程直到子進程返回.如果pid為正值則等待指定的進程(pid).如果為〇則等待任何ー個組ID和調用者的組ID相同的進程.為T時等同于wait調用.小于ー1時等待任何一個組ID等于pid絕對值的進程.stat_loc和wait的意義ー樣.options可以決定父進程的狀態.可以取兩個值WNOHANG:父進程立即返回當沒有子進程存在時.WUNTACHED:當子進程結束時waitpid返回,但是子進程的退出狀態不可得到.父進程創建子進程后,子進程一般要執行不同的程序.為了調用系統程序,我們可以使用系統調用exec族調用.exec族調用有著5個函數.#include<unistd.h>intexecl(constchar*path,constchar*arg,...);intexeclp(constchar*file,constchar*arg,...);intexecle(constchar*path,constchar*arg,...);intexecv(constchar*path,char*constargvロ);intexecvp(constchar*file,char*constargvロ);exec族調用可以執行給定程序,關于exec族調用的詳細解說可以參考系統手冊(manexec1),下面我們來學習ー個實例.注意編譯的時候要加Tm以便連接數學函數庫.#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>#include<stdio.h>#include<errno.h>#include<math.h>voidmain(void)Ipid_tchild;intstatus;printflThiswilldemostratehowtogetchildstatus'n");if((child=fork())—-1)printf(〃ForkError:%s\n,strerror(errno));exit(1);elseif(child=O)inti;printf(*1amthechild:%ld\n*,getpidO);for(i=0;i<1000000;i++)sin(i);i=5;printf(*1exitwith%d\n”,i);exit(i);}while(((child=wait(&status))=-1)&(errno=EINTR));if(child==-l)printf("WaitError:%s\n",strerror(errno)):elseif(!status)printf("Child%ldterminatednormallyreturnstatusiszero\n",child);elseif(WIFEXITED(status))printf("Child%ldterminatednormallyreturnstatusis%d\n",child,WEXITSTATUS(status));elseif(WlFSIGNALED(status))printf("Child%ldterminatedduetosignal%dznotcaught\n",child,WTERMSIG(status));)strerror函數會返回一個指定的錯誤號的錯誤信息的字符串.4。守護進程的創建如果你在DOS時代編寫過程序,那么你也許知道在DOS下為了編寫ー個常駐內存的程序我們要編寫多少代碼了.相反如果在Linux下編寫ー個"常駐內存"的程序卻是很容易的.我們只要幾行代碼就可以做到.實際上由于Linux是多任務操作系統,我們就是不編寫代碼也可以把一個程序放到后臺去執行的.我們只要在命令后面加上&符號SHELL就會把我們的程序放到后臺去運行的.這里我們"開發"ー個后臺檢查郵件的程序.這個程序每隔ー個指定的時間回去檢查我們的郵箱,如果發現我們有郵件了,會不斷的報警(通過機箱上的小喇叭來發出聲音).后面有這個函數的加強版本后臺進程的創建思想:首先父進程創建一個子進程.然后子進程殺死父進程(是不是很無情?).信號處理所有的工作由子進程來處理.Sinclude<unistd.h>^include<sys/types.h>ftinclude<sys/stat.h>#include<stdio.h>ttinclude<errno.h>#include<fcntl.h>#include<signal.h>/*Linux的默任個人的郵箱地址是/var/spool/mail/用戶的登錄名?/#defineMAIL*/var/spool/mai1/hoyt*/?睡眠10秒鐘?/#defineSLEEP_TIME10main(void)Ipid_tchild;if((child=fork())=-1)(printf("ForkError:%s\n",strerror(errno));exit(1);)elseif(child>0)while(l);if(kill(getppid(),SIGTERM)==-1)iprintf("KillParentError:%s\n",strerror(errno));exit(1);}(intmailfd;while(l)if((mailfd=open(MAIL,O_RDONLY))!=-l)fprintf(stderr,*%s*,*\007*);close(mailfd);sleep(SLEEP_TIME);你可以在默認的路徑下創建你的郵箱文件,然后測試ー下這個程序.當然這個程序還有很多地方要改善的.我們后面會對這個小程序改善的,再看我的改善之前你可以嘗試自己改善一下.比如讓用戶指定郵箱的路徑和睡眠時間等等.相信自己可以做到的.動手吧,勇敢的探險者.好了進程一節的內容我們就先學到這里了.進程是ー個非常重要的概念,許多的程序都會用子進程.創建一個子進程是每一個程序員的基本要求!3)Linux程序設計入門一文件操作Linux下文件的操作前言:我們在這ー節將要討論linux下文件操作的各個函數.文件的創建和讀寫文件的各個屬性目錄文件的操作管道文件1.文件的創建和讀寫我假設你已經知道了標準級的文件操作的各個函數(fopen,fread,fwrite等等).當然如果你不清楚的話也不要著急.我們討論的系統級的文件操作實際上是為標準級文件操作服務的.當我們需要打開一個文件進行讀寫操作的時候,我們可以使用系統調用函數open.使用完成以后我們調用另外?個close函數進行關閉操作.#include<fcntl.h>Sinclude<unistd.h>^include<sys/types.h>Sinclude<sys/stat.h>intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);intclose(intfd);open函數有兩個形式.其中pathname是我們要打開的文件名(包含路徑名稱,缺省是認為在當前路徑下面).flags可以去下面的一個值或者是幾個值的組合.O_RDONLY:以只讀的方式打開文件.O_WRONLY:以只寫的方式打開文件.0RDWR:以讀寫的方式打開文件.(LAPPEND:以追加的方式打開文件.O_CREAT:創建一個文件.0.EXEC:如果使用了0/REAT而且文件已經存在,就會發生一個錯誤.0NOBLOCK:以非阻塞的方式打開ー個文件.O_TRUNC:如果文件已經存在,則刪除文件的內容.前面三個標志只能使用任意的ー個.如果使用了O_CREATE標志,那么我們要使用open的第二種形式.還要指定mode標志,用來表示文件的訪問權限.mode可以是以下情況的組合.S」RUSR用戶可以讀S_IWUSR用戶可以寫S_IXUSR用戶可以執行S.IRWXU用戶可以讀寫執行SIRGRP組可以讀S_IWGRP組可以寫S_IXGRP組可以執行SIRWXG組可以讀寫執行S_IROTH其他人可以讀SIWOTH其他人可以寫S_IXOTH其他人可以執行S_IRWXO其他人可以讀寫執行SJSUID設置用戶執行IDS_ISGID設置組的執行ID我們也可以用數字來代表各個位的標志.Linux總共用5個數字來表示文件的各種權限.00000.第一位表示設置用戶ID.第二位表示設置組ID,第三位表示用戶自己的權限位,第四位表示組的權限,最后一位表示其他人的權限.每個數字可以取1(執行權限),2(寫權限),4(讀權限),0(什么也沒有)或者是這幾個值的和..比如我們要創建一個用戶讀寫執行,組沒有權限,其他人讀執行的文件.設置用戶ID位那么我們可以使用的模式是ー1(設置用戶ID)0(組沒有設置)7(1+2+4)0(沒有?權限,使用缺省)5(1+4)即!0705:open("temp”,0CREAT,10705);如果我們打開文件成功,open會返回一個文件描述符.我們以后對文件的所有操作就可以對這個文件描述符進行操作了.當我們操作完成以后,我們要關閉文件了,只要調用close就可以了,其中fd是我們要關閉的文件描述符.文件打開了以后,我們就要對文件進行讀寫了.我們可以調用函數read和write進行文件的讀寫.#include<unistd.h>ssize_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,constvoid*buffer,size_tcount);fd是我們要進行讀寫操作的文件描述符,buffer是我們要寫入文件內容或讀出文件內容的內存地址.count是我們要讀寫的字節數.對于普通的文件read從指定的文件(fd)中讀取count字節到buffer緩沖區中(記住我們必須提供?個足夠大的緩沖區),同時返回count.如果read讀到了文件的結尾或者被一個信號所中斷,返回值會小于count?如果是由信號中斷引起返回,而且沒有返回數據,read會返回ー1,且設置errno為EINTR.當程序讀到了文件結尾的時候,read會返回0.write從buffer中寫count字節到文件fd中,成功時返回實際所寫的字節數.下面我們學習ー個實例,這個實例用來拷貝文件.#include<unistd.h>ftinclude<fcntl.h>#include<stdio.h>ttinclude<sys/types.h>#include<sys/stat.h>ttinclude<errno.h>#include<string.h>#defineBUFFER_SIZE1024intmain(intargc,char**argv)Iintfrom_fd,to_fd;intbytes_read,byteswrite;charbuffer[BUFFER_SIZE];char*ptr;if(argc!=3)(fprintf(stderr,“Usage:%sfromfiletofile\n\a",argv[0]);exit(1);}/?打開源文件?/if((from_fd=open(argv[1],0RDONLY))==-1)ifprintf(stderr,*0pen%sError:%s\n/z,argv[1],strerror(errno));exit(1);}/?創建目的文件?/if((to_fd=open(argv[2],0_WR0NLYIO_CREAT,S_IRUSR|S_IWUSR))==-1)fprintf(stderr,"Open%sError:%s\n",argv[2],strerror(errno));exit(1);/*以下代碼是ー個經典的拷貝文件的代碼?/while(bytes_read=read(from_fd,buffer,BUFFER_SIZE))I/?ー個致命的錯誤發生了?/if((bytes_read==-l)&&(errno!=EINTR))break;elseif(bytes_read>0)(ptr=buffer;while(bytes_write=write(to_fd,ptr,bytes_read)){/?一個致命錯誤發生了?/if((bytes_write==-l)&&(errno!=EINTR))break;/?寫完了所有讀的字節?/elseif(bytes_write==bytes_read)break;/*只寫了一部分,繼續寫?/elseif(bytes__write>0)(ptr+=bytes_write;bytes_read-=bytes_write;))/?寫的時候發生的致命錯誤*/if(bytes_write==-l)break;})close(from_fd);close(tofd);exit(0);2〇文件的各個屬性文件具有各種各樣的屬性,除了我們上面所知道的文件權限以外,文件還有創建時間,大小等等屬性.有時侯我們要判斷文件是否可以進行某種操作(讀,寫等等).這個時候我們可以使用access函數.#include<unistd.h>intaccess(constchar*pathname,intmode);pathname:是文件名稱,mode是我們要判斷的屬性.可以取以下值或者是他們的組合.R_OK文件可以讀,W_0K文件可以寫,X_OK文件可以執行,F_OK文件存在.當我們測試成功時,函數返回0,否則如果有一個條件不符時,返回T.如果我們要獲得文件的其他屬性,我們可以使用函數stat或者fstat.#include<sys/stat.h>#include<unistd.h>intstat(constchar*filename,structstat*buf);intfstat(intfiledes,structstat*buf);structstat{dev_tst_dev;/*設備?/ino_tst_ino;/*節點*/mode_tst_mode;/?模式?/nlink_tst_nlink;/?硬連接?/uid_tst_uid;/?用戶ID*/gid_tst_gid;/?組!D*/dev_tst_rdev;/?設備類型?/off_tst_off;/?文件字節數?/unsignedlongstblksize;/?塊大小?/unsignedlongst_blocks;/?塊數?/time_tst_atime;/*最后一次訪問時間?/time_tst_mtime;/*最后一次修改時間?/timetst_ctime;/*最后一次改變時間(指屬性)*/};stat用來判斷沒有打開的文件,而fstat用來判斷打開的文件.我們使用最多的屬性是stmode.通過這屬性我們可以判斷給定的文件是一個普通文件還是一個目錄,連接等等.可以使用下面幾個宏來判斷.S_ISLNK(st_mode):是否是?個連接.S」SREG是否是ー個常規文件.SJSDIR是否是ー個目錄S_ISCHR是否是ー個字符設備.SJSBLK是否是ー個塊設備SJSFIFO是否是ー個FIFO文件.SJSSOCK是否是ー個SOCKET文件.我們會在下面說明如何使用這幾個宏的.3〇目錄文件的操作在我們編寫程序的時候,有時候會要得到我們當前的工作路徑。C庫函數提供了getcwd來解決這個問題。Sinclude<unistd.h>char*getcwd(char*buffer,size_tsize);我們提供ー個size大小的buffer,getcwd會把我們當前的路徑考到buffer中.如果buffer太小,函數會返回一1和一個錯誤號.Linux提供了大量的目錄操作函數,我們學習幾個比較簡單和常用的函數.#include<dirent.h>#include<unistd.h>ftinclude<fcntl.h>#include<sys/types.h>#include<sys/stat.h>intmkdir(constchar*path,modetmode);DIR*opendir(constchar*path);structdirent*readdir(DIR*dir);voidrewinddir(DIR*dir);off_ttelldir(DIR*dir);voidseekdir(DIR*dir,off_toff);intclosedir(DIR*dir);structdirent{longdino;off_td_off;unsignedshortd_reclen;chard_name[NAME_MAX+l];/?文件名稱?/)mkdir很容易就是我們創建一個目錄,opendir打開一個目錄為以后讀做準備.readdir讀ー個打開的目錄.rewinddir是用來重讀目錄的和我們學的rewind函數ー樣.closedir是關閉ー個目錄.telldir和seekdir類似與ftee和fseek函數.下面我們開發ー個小程序,這個程序有一個參數.如果這個參數是一個文件名,我們輸出這個文件的大小和最后修改的時間,如果是?個目錄我們輸出這個目錄下所有文件的大小和修改時間.#include<unistd.h>#include<stdio.h>#include<errno.h>#include<sys/types.h>#include<sys/stat.h>#include<dirent.h>include<time.h>staticintget_file_size_time(constchar*filename)(structstatstatbuf;if(stat(filename,&statbuf)ニニT)(printflGetstaton%sError:%s\nzz,filename,strerror(errno));return(-1);)if(S_ISDIR(statbuf.st_mode))return(1);if(S_ISREG(statbuf.st_mode))printf(*%ssize:%ldbytes\tmodifiedat%s”,filename,statbuf.st_size,ctime(&statbuf.stmtime));return(0);}intmain(intargc,char**argv)iDIR*dirp;structdirent*direntp;intstats;if(argc!=2)printf(,zUsage:%sfilename\n\az/,argv[O]);exit(1);)if(((stats=get_file_size_time(argv[l]))==O)||(stats==-l))exit(1);if((dirp=opendir(argv[1]))==NULL)(printf("OpenDirectory%sError:%s\n",argv[l],strerror(errno));exit(1);)while((direntp=readdir(dirp))!=NULL)if(getfi1e_size_time(direntp-<d_name)==-1)break;closedir(dirp);exit(1);4?管道文件Linux提供了許多的過濾和重定向程序,比如morecat等等.還提供了〈>|くく等等重定向操作符.在這些過濾和重定向程序當中,都用到了管道這種特殊的文件.系統調用pipe可以創建一個管道.#include<unistd.h>intpipe(intfildes⑵);pipe調用可以創建一個管道(通信緩沖區).當調用成功時,我們可以訪問文件描述符fildes[

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論