日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下的C编程实战之文件系统编程

發(fā)布時(shí)間:2023/11/30 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下的C编程实战之文件系统编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

 在Linux平臺下對文件編程可以使用兩類函數(shù):(1Linux操作系統(tǒng)文件API;(2C語言I/O庫函數(shù)。前者依賴于Linux系統(tǒng)調(diào)用,后者實(shí)際上與操作系統(tǒng)是獨(dú)立的,因?yàn)樵谌魏尾僮飨到y(tǒng)下,使用C語言I/O庫函數(shù)操作文件的方法都是相同的。本章將對這兩種方法進(jìn)行實(shí)例講解。


1. 文件IO操作


S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP


? fd=open("/dev/globalvar", O_RDWR, S_IRUSR|S_IWUSR); ? ? //可讀寫方式打開設(shè)備文件

S_IRUSR

Permits the file's owner to read it.
S_IWUSR
Permits the file's owner to write to it.
S_IRGRP
Permits the file's group to read it.
S_IWGRP
Permits the file's group to write to it.
S_ISDIR ( ) 目錄文件
S_ISCHR ( ) 字符特殊文件
S_ISBLK ( ) 塊特殊文件
S_ISFIFO ( ) 管道或F I F O
S_ISLNK ( ) 符號連接( P O S I X . 1S V R 4無此類型)
S_ISSOC K ( ) 套接字(P O S I X . 1S V R 4無此類型)

S_ISREG ( ) 普通文件



   2.Linux 文件 API

   Linux 的文件操作 API 涉及到創(chuàng)建、打開、讀寫和關(guān)閉文件。

  創(chuàng)建

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


  參數(shù)mode指定新建文件的存取權(quán)限,它同umask一起決定文件的最終權(quán)限(mode&umask),其中umask代表了文件在創(chuàng)建時(shí)需要去掉的一些存取權(quán)限。umask可通過系統(tǒng)調(diào)用umask()來改變:

int umask(int newmask);


  該調(diào)用將umask設(shè)置為newmask,然后返回舊的umask,它只影響讀、寫和執(zhí)行權(quán)限。

  打開

int open(const char *pathname, int flags);?

int open(const char *pathname, int flags, mode_t mode);


  open函數(shù)有兩個(gè)形式,其中pathname是我們要打開的文件名(包含路徑名稱,缺省是認(rèn)為在當(dāng)前路徑下面)flags可以去下面的一個(gè)值或者是幾個(gè)值的組合:

標(biāo)志含義

O_RDONLY以只讀的方式打開文件

O_WRONLY以只寫的方式打開文件

O_RDWR以讀寫的方式打開文件

O_APPEND以追加的方式打開文件

O_CREAT 創(chuàng)建一個(gè)文件

O_EXEC如果使用了O_CREAT而且文件已經(jīng)存在,就會發(fā)生一個(gè)錯(cuò)誤

O_NOBLOCK以非阻塞的方式打開一個(gè)文件

O_TRUNC如果文件已經(jīng)存在,則刪除文件的內(nèi)容

? ?


  O_RDONLYO_WRONLYO_RDWR三個(gè)標(biāo)志只能使用任意的一個(gè)。

  如果使用了O_CREATE標(biāo)志,則使用的函數(shù)是int open(const char *pathname,int flags,mode_t mode);這個(gè)時(shí)候我們還要指定mode標(biāo)志,用來表示文件的訪問權(quán)限。mode可以是以下情況的組合:

標(biāo)志含義

S_IRUSR 用戶可以讀

S_IWUSR 用戶可以寫

S_IXUSR 用戶可以執(zhí)行

S_IRWXU用戶可以讀、寫、執(zhí)行

S_IRGRP 組可以讀

S_IWGRP 組可以寫

S_IXGRP 組可以執(zhí)行

S_IRWXG 組可以讀寫執(zhí)行

S_IROTH 其他人可以讀

S_IWOTH 其他人可以寫

S_IXOTH 其他人可以執(zhí)行

S_IRWXO其他人可以讀、寫、執(zhí)行

S_ISUID 設(shè)置用戶執(zhí)行ID

S_ISGID 設(shè)置組的執(zhí)行ID


  除了可以通過上述宏進(jìn)行邏輯產(chǎn)生標(biāo)志以外,我們也可以自己用數(shù)字來表示,Linux總共用5個(gè)數(shù)字來表示文件的各種權(quán)限:第一位表示設(shè)置用戶ID;第二位表示設(shè)置組ID;第三位表示用戶自己的權(quán)限位;第四位表示組的權(quán)限;最后一位表示其他人的權(quán)限。每個(gè)數(shù)字可以取1(執(zhí)行權(quán)限)2(寫權(quán)限)4(讀權(quán)限)0()或者是這些值的和。例如,要創(chuàng)建一個(gè)用戶可讀、可寫、可執(zhí)行,但是組沒有權(quán)限,其他人可以讀、可以執(zhí)行的文件,并設(shè)置用戶ID位。那么,我們應(yīng)該使用的模式是1(設(shè)置用戶ID)0(不設(shè)置組ID)7(1+2+4,讀、寫、執(zhí)行)0(沒有權(quán)限)5(1+4,讀、執(zhí)行)10705

open("test", O_CREAT, 10705);


  上述語句等價(jià)于:

open("test", O_CREAT, S_IRWXU | S_IROTH | S_IXOTH | S_ISUID );


  如果文件打開成功,open函數(shù)會返回一個(gè)文件描述符,以后對該文件的所有操作就可以通過對這個(gè)文件描述符進(jìn)行操作來實(shí)現(xiàn)。

  讀寫

  在文件打開以后,我們才可對文件進(jìn)行讀寫了,Linux中提供文件讀寫的系統(tǒng)調(diào)用是readwrite函數(shù):

int read(int fd, const void *buf, size_t length);

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


  其中參數(shù)buf為指向緩沖區(qū)的指針,length為緩沖區(qū)的大小(以字節(jié)為單位)。函數(shù)read()實(shí)現(xiàn)從文件描述符fd所指定的文件中讀取length個(gè)字節(jié)到buf所指向的緩沖區(qū)中,返回值為實(shí)際讀取的字節(jié)數(shù)。函數(shù)write實(shí)現(xiàn)將把length個(gè)字節(jié)從buf指向的緩沖區(qū)中寫到文件描述符fd所指向的文件中,返回值為實(shí)際寫入的字節(jié)數(shù)。

  以O_CREAT為標(biāo)志的open實(shí)際上實(shí)現(xiàn)了文件創(chuàng)建的功能,因此,下面的函數(shù)等同creat()函數(shù):

int open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);


  定位

  對于隨機(jī)文件,我們可以隨機(jī)的指定位置讀寫,使用如下函數(shù)進(jìn)行定位:

int lseek(int fd, offset_t offset, int whence);


  lseek()將文件讀寫指針相對whence移動offset個(gè)字節(jié)。操作成功時(shí),返回文件指針相對于文件頭的位置。參數(shù)whence可使用下述值:

  SEEK_SET:相對文件開頭
  SEEK_CUR:相對文件讀寫指針的當(dāng)前位置
  SEEK_END:相對文件末尾

  offset可取負(fù)值,例如下述調(diào)用可將文件指針相對當(dāng)前位置向前移動5個(gè)字節(jié):

lseek(fd, -5, SEEK_CUR);


  由于lseek函數(shù)的返回值為文件指針相對于文件頭的位置,因此下列調(diào)用的返回值就是文件的長度:

lseek(fd, 0, SEEK_END);


  關(guān)閉

  當(dāng)我們操作完成以后,我們要關(guān)閉文件了,只要調(diào)用close就可以了,其中fd是我們要關(guān)閉的文件描述符:

int close(int fd);


  例程:編寫一個(gè)程序,在當(dāng)前目錄下創(chuàng)建用戶可讀寫文件“hello.txt”,在其中寫入“Hello, software weekly”,關(guān)閉該文件。再次打開該文件,讀取其中的內(nèi)容并輸出在屏幕上。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#define LENGTH 100

main()

{

 int fd, len;

 char str[LENGTH];?

 fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /*創(chuàng)建并打開文件 */

 if (fd)?

 {

  write(fd, "Hello, Software Weekly", strlen("Hello, software weekly")); /*寫入 Hello, software weekly字符串 */

  close(fd);

 }


 fd = open("hello.txt", O_RDWR);

 len = read(fd, str, LENGTH); /*讀取文件內(nèi)容 */

 str[len] = '\0';

 printf("%s\n", str);

 close(fd);

}


 3.C語言庫函數(shù)

  C庫函數(shù)的文件操作實(shí)際上是獨(dú)立于具體的操作系統(tǒng)平臺的,不管是在DOSWindowsLinux還是在VxWorks中都是這些函數(shù):

  創(chuàng)建和打開

FILE *fopen(const char *path, const char *mode);


  fopen()實(shí)現(xiàn)打開指定文件filename,其中的mode為打開模式,C語言中支持的打開模式如下表:

標(biāo)志含義

r, rb以只讀方式打開

w, wb以只寫方式打開。如果文件不存在,則創(chuàng)建該文件,否則文件被截?cái)?/p>

a, ab以追加方式打開。如果文件不存在,則創(chuàng)建該文件

r+, r+b, rb+ 以讀寫方式打開

w+, w+b, wh+以讀寫方式打開。如果文件不存在時(shí),創(chuàng)建新文件,否則文件被截?cái)?/p>

a+, a+b, ab+以讀和追加方式打開。如果文件不存在,創(chuàng)建新文件


  其中b用于區(qū)分二進(jìn)制文件和文本文件,這一點(diǎn)在DOSWindows系統(tǒng)中是有區(qū)分的,但Linux不區(qū)分二進(jìn)制文件和文本文件。

  讀寫

  C庫函數(shù)支持以字符、字符串等為單位,支持按照某中格式進(jìn)行文件的讀寫,這一組函數(shù)為:

int fgetc(FILE *stream);

int fputc(int c, FILE *stream);

char *fgets(char *s, int n, FILE *stream);

int fputs(const char *s, FILE *stream);

int fprintf(FILE *stream, const char *format, ...);

int fscanf (FILE *stream, const char *format, ...);

size_t fread(void *ptr, size_t size, size_t n, FILE *stream);

size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream);


  fread()實(shí)現(xiàn)從流stream中讀取加n個(gè)字段,每個(gè)字段為size字節(jié),并將讀取的字段放入ptr所指的字符數(shù)組中,返回實(shí)際已讀取的字段數(shù)。在讀取的字段數(shù)小于num時(shí),可能是在函數(shù)調(diào)用時(shí)出現(xiàn)錯(cuò)誤,也可能是讀到文件的結(jié)尾。所以要通過調(diào)用feof()ferror()來判斷。

  write()實(shí)現(xiàn)從緩沖區(qū)ptr所指的數(shù)組中把n個(gè)字段寫到流stream中,每個(gè)字段長為size個(gè)字節(jié),返回實(shí)際寫入的字段數(shù)。

  另外,C庫函數(shù)還提供了讀寫過程中的定位能力,這些函數(shù)包括

int fgetpos(FILE *stream, fpos_t *pos);

int fsetpos(FILE *stream, const fpos_t *pos);

int fseek(FILE *stream, long offset, int whence);?

等。


  關(guān)閉

  利用C庫函數(shù)關(guān)閉文件依然是很簡單的操作:

int fclose (FILE *stream);


  例程:將第2節(jié)中的例程用C庫函數(shù)來實(shí)現(xiàn)。

#include <stdio.h>

#define LENGTH 100

main()

{

 FILE *fd;

 char str[LENGTH];


 fd = fopen("hello.txt", "w+"); /*創(chuàng)建并打開文件 */

 if (fd)

 {

  fputs("Hello, Software Weekly", fd); /*寫入Hello, software weekly字符串 */

  fclose(fd);

 }


 fd = fopen("hello.txt", "r");

 fgets(str, LENGTH, fd); /*讀取文件內(nèi)容 */

 printf("%s\n", str);

 fclose(fd);

}


  4.小結(jié)

  Linux提供的虛擬文件系統(tǒng)為多種文件系統(tǒng)提供了統(tǒng)一的接口,Linux的文件編程有兩種途徑:基于Linux系統(tǒng)調(diào)用;基于C庫函數(shù)。這兩種編程所涉及到文件操作有新建、打開、讀寫和關(guān)閉,對隨機(jī)文件還可以定位。本章對這兩種編程方法都給出了具體的實(shí)例。



帶緩沖I/O 不帶緩沖I/O詳解


?以下是我對這兩者的理解:

首先要明白不帶緩沖的概念:所謂不帶緩沖,并不是指內(nèi)核不提供緩沖,而是只單純的系統(tǒng)調(diào)用,不是函數(shù)庫的調(diào)用。系統(tǒng)內(nèi)核對磁盤的讀寫都會提供一個(gè)塊緩沖,當(dāng)用write函數(shù)對其寫數(shù)據(jù)時(shí),直接調(diào)用系統(tǒng)調(diào)用,將數(shù)據(jù)寫入到塊緩沖進(jìn)行排隊(duì),當(dāng)塊緩沖達(dá)到一定的量時(shí),才會把數(shù)據(jù)寫入磁盤。因此所謂的不帶緩沖的I/O是指進(jìn)程不提供緩沖功能。每調(diào)用一次writeread函數(shù),直接系統(tǒng)調(diào)用。

而帶緩沖的I/O是指進(jìn)程對輸入輸出流進(jìn)行了改進(jìn),提供了一個(gè)流緩沖,當(dāng)用fwrite函數(shù)網(wǎng)磁盤寫數(shù)據(jù)時(shí),先把數(shù)據(jù)寫入流緩沖區(qū)中,當(dāng)達(dá)到一定條件,比如流緩沖區(qū)滿了,或刷新流緩沖,這時(shí)候才會把數(shù)據(jù)一次送往內(nèi)核提供的塊緩沖,再經(jīng)塊緩沖寫入磁盤。

因此,帶緩沖的I/O在往磁盤寫入相同的數(shù)據(jù)量時(shí),會比不帶緩沖的I/O調(diào)用系統(tǒng)調(diào)用的次數(shù)要少。


下面的東西是我從網(wǎng)上查到的對這兩者的理解,我覺得還是很到位的:

以下主要討論關(guān)于open,write等基本系統(tǒng)IO的帶緩沖與不帶緩沖的差別


? ? ? 帶緩存的文件操作是標(biāo)準(zhǔn)C 庫的實(shí)現(xiàn),第一次調(diào)用帶緩存的文件操作函數(shù)時(shí)標(biāo)準(zhǔn)庫會自動分配內(nèi)存并且讀出一段固定大小的內(nèi)容存儲在緩存中。所以以后每次的讀寫操作并不是針對硬盤上的文 件直接進(jìn)行的,而是針對內(nèi)存中的緩存的。何時(shí)從硬盤中讀取文件或者向硬盤中寫入文件有標(biāo)準(zhǔn)庫的機(jī)制控制。不帶緩存的文件操作通常都是系統(tǒng)提供的系統(tǒng)調(diào)用, 更加低級,直接從硬盤中讀取和寫入文件,由于IO瓶頸的原因,速度并不如意,而且原子操作需要程序員自己保證,但使用得當(dāng)?shù)脑捫什⒉徊睢A硗鈽?biāo)準(zhǔn)庫中的 帶緩存文件IO 是調(diào)用系統(tǒng)提供的不帶緩存IO實(shí)現(xiàn)的。


術(shù)語不帶緩沖指的是每個(gè)readwrite都調(diào)用嗯內(nèi)核中的一個(gè)系統(tǒng)調(diào)用。所有的磁盤I/O都要經(jīng)過內(nèi)核的塊緩沖(也稱內(nèi)核的緩沖區(qū)高速緩 存),唯一例外的是對原始磁盤設(shè)備的I/O。既然readwrite的數(shù)據(jù)都要被內(nèi)核緩沖,那么術(shù)語不帶緩沖的I/O“指的是在用戶的進(jìn)程中對這兩個(gè) 函數(shù)不會自動緩沖,每次readwrite就要進(jìn)行一次系統(tǒng)調(diào)用。“--------摘自<unix環(huán)境編程>


程序中用openwrite打開創(chuàng)建并把“hello world“寫入文件test.txt,相應(yīng)用fopenfwrite操作文件test2.txt。程序執(zhí)行到openfopen之后,sleep 15秒,這時(shí)用ls查看生成了文件沒,這時(shí)用open打開的test.txt出現(xiàn)了,但是fopentest2.txt沒有;當(dāng)程序執(zhí)行完write fwrite之后,fopentest2.txt仍然沒有出現(xiàn)(還是用ls查看),再用cattest.txt,可以看到 “helloworld”;最后再關(guān)閉test.txttest2.txt,這時(shí)test2.txt出現(xiàn)了,并且其內(nèi)容也是“hello world“

?? 該例子證明了openwrite是不帶緩沖的,即程序一執(zhí)行其io操作也立即執(zhí)行,不會停留在系統(tǒng)提供的緩沖里,不需等到close操作完才執(zhí)行。與之相比的fopenfwrite則是帶緩沖的,(一般)要等到fclose操作完后才會執(zhí)行。

??

? 相關(guān)的源碼示例如下:

?i nclude <unistd.h>

i nclude <iostream>

i nclude <fcntl.h>

i nclude <string>

i nclude <sys/types.h>

i nclude <sys/stat.h>

using namespace std;


int main(){

?int fd;

?FILE *file;

?char *s="hello,world\n";

?if((fd=open("test.txt",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1){

? cout<<"Error open file"<<endl;

? return -1;

?}

?if((file=fopen("test2.txt","w"))==NULL){

? cout<<"Error Open File."<<endl;

? return -1;

?}

?cout<<"File has been Opened."<<endl;

?sleep(15);

?if(write(fd,s,strlen(s))<strlen(s)){

? cout<<"Write Error"<<endl;

? return -1;

?}

?if(fwrite(s,sizeof(char),strlen(s),file)<strlen(s)){

? cout<<"Write Error in 2."<<endl;

? return -1;

?}

?cout<<"After write"<<endl;

?sleep(15);

?cout<<"After sleep."<<endl;

?close(fd);

?return 0;

}

詳情請見:http://blog.csai.cn/user1/27828/archives/2007/14285.html


ssize_t write(int filedes, const void *buff, size_t nbytes)size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp)來講講自己對unix系統(tǒng)下帶緩存的I/O和不帶緩存的I/O的區(qū)別。


?

? ? 首先要清楚一個(gè)概念,所謂的代緩存并不是指上面兩個(gè)函數(shù)的buff參數(shù),而是指unix系統(tǒng)在內(nèi)核中所設(shè)的緩沖存儲器。


? ? 當(dāng)將數(shù)據(jù)寫到文件上時(shí),內(nèi)核先將該數(shù)據(jù)寫到緩存,如果該緩存未滿,則并不將其排入輸出隊(duì)列,直到緩存寫滿或者內(nèi)核再次需要重新使用此緩存時(shí)才將其排入輸入隊(duì)列,待其到達(dá)對首,在進(jìn)行實(shí)際的I/O操作,也就是此時(shí)才把數(shù)據(jù)真正寫到磁盤,這種技術(shù)叫延遲寫。


? ? 現(xiàn)在假設(shè)內(nèi)核所設(shè)的緩存是100個(gè)字節(jié),如果你使用write,且buffsize10,當(dāng)你要把9個(gè)同樣的buff寫到文件時(shí),你需要調(diào)用9write,也就是9次系統(tǒng)調(diào)用,此時(shí)也并沒有寫到硬盤,如果想立即寫到硬盤,調(diào)用fsync,可以進(jìn)行實(shí)際的I/O操作。


? ? 標(biāo)準(zhǔn)I/O,也就是帶緩存的I/O采用FILE*FILE實(shí)際上包含了為管理流所需要的所有信息:實(shí)際I/O的文件描述符,指向流緩存的指針(標(biāo)準(zhǔn)I /O緩存,由malloc分配,又稱為用戶態(tài)進(jìn)程空間的緩存,區(qū)別于內(nèi)核所設(shè)的緩存),緩存長度,當(dāng)前在緩存中的字節(jié)數(shù),出錯(cuò)標(biāo)志等,假設(shè)流緩存的長度為 50字節(jié),把以上的數(shù)據(jù)寫到文件,則只需要2次系統(tǒng)調(diào)用(fwrite調(diào)用write系統(tǒng)調(diào)用),因?yàn)橄劝褦?shù)據(jù)寫到流緩存,當(dāng)其滿以后或者調(diào)用 fflush時(shí)才填入內(nèi)核緩存,所以進(jìn)行了2次的系統(tǒng)調(diào)用write


? ? fflush將流所有未寫的數(shù)據(jù)送入(刷新)到內(nèi)核(內(nèi)核緩沖區(qū)),fsync將所有內(nèi)核緩沖區(qū)的數(shù)據(jù)寫到文件(磁盤)。

?

? ? 不帶緩存的readwrite是相對于fread/fwrite等流函數(shù)來說明的,因?yàn)?span style="line-height:normal; font-family:Helvetica">fread和fwrite是用戶函數(shù)(3),所以他們會在用戶層 進(jìn)行一次數(shù)據(jù)的緩存,而read/write是系統(tǒng)調(diào)用(2)所以他們在用戶層是沒有緩存的,所以稱readwrite是無緩存的IO,其實(shí)對于內(nèi)核來 說還是進(jìn)行了緩存,不過用戶層看不到罷了。




總結(jié)

以上是生活随笔為你收集整理的Linux下的C编程实战之文件系统编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。