linux 檔案讀寫

來源:互聯網
上載者:User

 

   兩種I/O檔案函數
  • fopen  
     ANSI 標準檔案I/O,基於低層次I/O
  • open    
    低層次I/O 

    ANSI I/O本質

  • DOS/WINDOWS平台,MS DOS 檔案讀寫, 組合語言編寫
  • LINUX平台,unix/linux檔案讀寫,C語言編寫

   檔案類型FILE

包含一個指標
包含一個stream (C語言把檔案看成stream

    file open

r    
   
 Open text file for reading
r+   
   
 Open for reading and writing
w    Truncate
file to zero length or create text file for writing
w+   
   
 The file is created if it does not exist,
otherwise it is truncated
a    
 Open  for 
appending (writing at end of file).  
The stream is positioned at the end of the file.

    fopen三種基本模式r,w,a只允許針對文本文

   
C語言允許最大同時開啟16個檔案

實際只允許同時開啟13個檔案,因為有另外三個標準檔案stdout,stdin,stderr

    
檔案讀寫的基本語句

 1 #include <stdio.h>
FILE
*stream; 注意類型是大寫
 2 if((stream=fopen("testtmp","r+"))==NULL)
{ printf("open file error/n");
  return;
}
 3 int ret;
if ((ret=fclose(stream))==-1) printf("close file
error/n");

  

    順序讀檔案(按字元)

while((c=fgetc(stream))!=
EOF
)
printf("%c",c);   
每讀一個字元,檔案指標會(自動)移動一格

   順序讀檔案(按字串)-------從一個檔案依次讀一行,直到讀到NULL

char record[100],*re;
while ((re=fgets(record,100
,stream))!=NULL
)
printf("%s",record);
 讀一行,以斷行符號換行作為讀一行的尾部標誌

    從檔案中fgets的字串是讀一行,即包括了斷行符號

所以printf("%s")即可,不用"%s/n",因為字串裡面帶了斷行符號了
這也是個漏洞,字串裡帶了斷行符號
所以非常不利於字串比對strcmp
  
  
scanf讀檔案,檔案指標不移動,需要手動fseek移指標

fseek(stream,3,SEEK_SET);
fscanf(stream,"%c",&c[0]);
fseek(stream,11,SEEK_SET);
fscanf(stream,"%c",&c[1]);

   檔案讀寫到檔案末尾

    檔案指標會指到NULL
(而不是EOF,EOF不是地址,而是結尾字元

  •    
    fput(),fgetc()會返回EOF
  •    
    fgets()會返回NULL

    linux和DOS對檔案的結束判別是不同的

linux沒有檔案結束符
,是以目錄項的檔案長度做為檔案結束的判別手段
DOS看0x1a檔案結束符

    linux 和DOS的分行符號的區別

 linux   DOS
0x0a   即
10

即’/n’
即LF
 CR,LF雙碼

  
    讀檔案時, 不能用unsigned char c作為傳回值,
因為EOF不在unsigned範圍內

char c;
c=getc(stream);   
  

    fscanf讀文字檔裡面的數字,既可以直接用%c,也可以用%d

用%c(char)讀,可以讀出3,1 用%d(int)讀,也可以讀出3,1
fseek(stream,3,SEEK_SET);
fscanf(stream,"%c",&c[0]);
fseek(stream,11,SEEK_SET);
fscanf(stream,"%c",&c[1]);
fseek(stream,ii,SEEK_SET);
fscanf(stream,"%d",&ln[i].frame);
fseek(stream,ii+8,SEEK_SET);
fscanf(stream,"%d",&ln[i].line);

只不過這兩個3,1,一個是實際值3,1,一個是'3','1'

    幾個常見特殊字元的整型數字

 char  int
 空格' '  32
 TAB鍵  9
 斷行符號  10
檔案結束EOF  -1
字串結束符號 數字0(不是字元‘0’)

 

    TAB字元處理要小心,經過到記事本copy/paste後,TAB鍵被轉化成幾個空格
  

for(;str[i]=='
'||str[i]=='   
   
';i++);
但經過到記事本copy/paste後,TAB鍵被轉化成幾個空格
所以系統總報warning:
tmp.c:58: warning: comparison is always false due to limited range
of data type
tmp.c:59:27: warning: character constant too long for its
type

   
   fgets字串指標改成字串數組,消滅了Segmentation
fault錯誤

char *re,*rec;
re=fgets(rec,100,srcstream);   

出Segmentation fault錯誤

改成
char *re,rec[100];
re=fgets(rec,100,srcstream);   

錯誤消失

  一個普通的顯示檔案內容
的函數

printfile(FILE *stream,char *filename,int or)
{
int i,re;
char rec[100];
FILE *tmpstream;
if (or)
 {
 if((tmpstream=fopen(filename,"r"))==NULL)
    {
printf("open file error/n");
     
return 0;
    
}
for(i=0;(re=fgets(rec,100,tmpstream))!=NULL;i++)
printf("[%d]:%s",i,rec);
顯示檔案內容時,每行加行號
 if ((re=fclose(tmpstream))==-1) printf("close
file error/n");

 } else
  {
fseek(stream,0,SEEK_SET);
for(i=0;(re=fgets(rec,100,stream))!=NULL;i++)
printf("[%d]:%s",i,rec);
  }
}    

printfile(NULL,"testtmp.tmp",1
);

[0]:total 48
[1]:1 macg macg 3301 Jan 16 02:16 file.c
[2]:-rw-rw-r--  1 macg
macg   52 Jan 16 02:19
Makefile
[3]:1 macg macg 0 Jan 16 02:56 testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis is
a testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56
tmp.o

if((stream=fopen("testtmp","r+"))==NULL)
{ printf("open file error/n");
  return 0;
}
printfile(stream
,NULL,0
);

[0]:total 48
[1]:-rw-rw-r--  1 macg macg 3301 Jan 16
02:16   
file.c
[2]:-rw-rw-r--  1 macg
macg   52 Jan 16 02:19
Makefile
[3]:   
-rw-rw-r--  1 macg
macg            
0 Jan
16    
02:56   testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis is
a testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56
tmp.o

    按SED/AWK原理,讀記錄/行的函數——是從檔案中取第recno行

int getrecord(char *rec,FILE *stream,int recno)
{
int i,ret;
char *re;
for(i=0;i<=recno;i++) re=fgets(rec,100,stream);
數行,並一邊數一邊讀行

if(re==NULL) return 0;  
如果所取行超過檔案長度,則返回0
 else return 1;
}

getrecord(record,stream,4);       
取記錄/行,取檔案第四行
printf("record is %s/n",record);
printf("/n/n/n");
$ ./tmp
record
is      
-rw-rw-r--  1 macg
macg            
0 Jan
16    
02:56   testtmp

        

    按SED/AWK原理,讀欄位的函數——從字串中取第valueno欄位

int getvalue(char *str,int valueno,char *value)
{
int i,j,vali;

數欄位

for(i=0,vali=0;vali<valueno;vali++)
{

for(;str[i]==' '||str[i]==9;i++);

for(;str[i]!='
'&&str[i]!=9&&str[i]!=0;i++);

if(str[i]==0) return 0;
}

取欄位

for(;str[i]==' '||str[i]==9;i++);

for(j=0;str[i]!='
'&&str[i]!=9&&str[i]!=0;i++,j++)

 {
  value[j]=str[i];
 }
value[j]=0;

}  

for(i=0;i<20;i++)          

{
if(getvalue(record,i,val)) printf("no %d is %s/n",i,val);
}

$ ./tmp
record
is      
-rw-rw-r--  1 macg
macg            
0 Jan
16    
02:56   testtmp 
  事先故意編輯過此行,加了幾個TAB,連行尾也含TAB
     

no 0 is -rw-rw-r--
no 1 is 1
no 2 is macg
no 3 is macg
no 4 is 0
no 5 is Jan
no 6 is 16
no 7 is 02:56
no 8 is testtmp
no 9 is

    fputs(stren,streamwrite)
寫入的串不帶斷行符號,fprintf(strea,"%s",str)寫入的串也不帶斷行符號,所以,要寫入檔案斷行符號,必須寫入/n

fputs(stren,streamwrite);

cat aaa.txt
008421aa

fprintf(streamwrite,"%s/n
",stren);

cat aaa.txt
008421

aa

    
檔案很難進行“修改寫”,建議檔案追加

   最好的辦法就是寫到新檔案
,或寫到stdout再重新導向入檔案。然後把新檔案覆蓋舊檔案

    writefile(char *tmpfilename,char
*srcfilename,struct Filerecord *frs,int
frsi)-------修改檔案的函數

實際是從 srcfile讀出檔案
把其中符合frs[j].recno的行,修改成frs[j].record
其他行不變,仍舊用srcfile讀出的行
然後把這些行重新寫入一個新檔案tmpfile

writefile(char *tmpfilename,char
*srcfilename,struct Filerecord *frs,int frsi
o    tmpfilename
新檔案名稱

o    srcfilename
舊檔案名稱

o    struct
Filerecord *frs  放置要修改的行的結構體數組
struct Filerecord{
char record[100];
int recno;
};
struct Filerecord fr[20];

o   
frsi  結構體數組的元素數量

writefile(char *tmpfilename,char *srcfilename,struct Filerecord
*frs,int frsi)
{
int no,ret,i,j,bol;
char *re,rec[100];
FILE *tmpstream,*srcstream;

if((tmpstream=fopen(tmpfilename,"w+
"))==NULL) 
寫入一個新
  {  
printf("open file error/n");
    
return 0;
    }
if((srcstream=fopen(srcfilename,"r"))==NULL)
  { printf("open file error/n");
   
return  0;
    }

for(no=0;(re=fgets(rec,100,srcstream))!=NULL;no++)
{
 for(j=0,bol=1;j<frsi&&bol;j++)

  {
   if(no==frs[j].recno) {
      
bol=0;
      
strcpy(rec,frs[j].record);
                                
}
   }

 fputs(rec,tmpstream);
}

if ((ret=fclose(tmpstream))==-1) printf("close file
error/n");
if ((ret=fclose(srcstream))==-1) printf("close file
error/n");

}   

例子:去掉檔案中行的TAB鍵和起首空格或TAB
執行:
   
讀出原檔案每行,checkinvaild() ,看是否含有TAB,起首空格/TAB
   
如果確實有,就對此行處理,重新組合,去掉TAB,起首空格/TAB,然後寫入struct person fr[20]數組
   
writefile("testtmp.tmp","testtmp",fr,fri);
------------------the sick
file----------------------------------------
[0]:total 48
[1]:-rw-rw-r--  1 macg macg 3301 Jan 16
02:16   
file.c
[2]:-rw-rw-r--  1 macg
macg   52 Jan 16 02:19
Makefile
[3]:   
-rw-rw-r--  1 macg
macg            
0 Jan
16    
02:56   testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis is
a testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56
tmp.o
--------------------modify
line--------------------------------------
fri is 2,the new line is following:
[1]row:1 macg macg 3301 Jan 16 02:16 file.c
[3]row:1 macg macg 0 Jan 16 02:56 testtmp
-------------------new
file---------------------------------------
[0]:total 48
[1]:1 macg macg 3301 Jan 16 02:16 file.c
[2]:-rw-rw-r--  1 macg
macg   52 Jan 16 02:19
Makefile
[3]:1 macg macg 0 Jan 16 02:56 testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis is
a testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56
tmp.o

    fseek(stream,offset,mode)的三個mode

SEEK_SET:從開頭數第幾個offset
SEEK_CUR: 從當前數第幾個offset
SEEK_END: 從結尾倒數第幾個offset

 
檔案指標位置是從0(檔案頭)開始算的

fseek(stream,0,SEEK_SET);

   int ftell(FILE
*stream)
  
  返回stream的當前指標位置

    簡單的取檔案大小size的操作

fseek(stream,0,SEEK_END);先將指標指向檔案尾部
ret=ftell(stream); 再獲得指標所指的當前地址
                
這個指向檔案尾部的指標地址就是檔案大小

  取檔案大小的操作對讀寫檔案很有用,因為讀寫檔案很不好判定檔案結尾。

    檔案例子

$ cat tmp.c
#define DEBUG 0

#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct Filerecord{
char record[100];
int recno;
};

main()
{
char directory[100];

#ifdef SYST
getcwd(directory,100);
printf("current directory is %s/n",directory);

#endif

 filemanage();
}

filemanage()
{
int i,j,fri,ret;
char record[100],val[50],modi_rec[100];
FILE *stream;
struct Filerecord fr[20];

if((stream=fopen("testtmp","r+"))==NULL)
{ printf("open file error/n");
  return 0;
}

printf("------------------the sick
file-----------------------/n");
printfile(stream,NULL,0);

for(i=0,fri=0;getrecord(record,stream,i);i++)
 {
if (DEBUG) printf("no %d row is:%s/n",i,record);
if(ret=findinvalid(record))
   
{  
  for(j=0;getvalue(record,j,val);j++)
       
{
if (DEBUG)  printf("no %d's val is %s
%d/n",j,val,val[0]);
     
if(j==1) strcpy(modi_rec,val);
     
if(j>1)  {
       
strcat(modi_rec," ");
       
strcat(modi_rec,val);
               
}
        
}
 fr[fri].recno=i;
 strcpy(fr[fri].record,modi_rec);
if (DEBUG) printf("fr[%d] is %d 
%s/n",fri,fr[fri].recno,fr[fri].record);
 fri++;
    
}
if (DEBUG) printf("---------------------------------/n");

 }
printf("--------------------modify
line--------------------/n");
printf("fri is %d,the new line is following: /n",fri);
for(i=0;i<fri;i++)
 printf("[%d]row:%s",fr[i].recno,fr[i].record);

if ((ret=fclose(stream))==-1)
  {
 printf("close file error/n");
 return 0;
  }
writefile("testtmp.tmp","testtmp",fr,fri);
printf("-------------------new file-----------------/n");
printfile(NULL,"testtmp.tmp",1);
}

int findinvalid(char *str)
{
int i,ret;
i=0;
if(str[i]==' ')
{
if (DEBUG) printf("str[%d] == %d/n",i,str[i]);
 return 32;
}
for(i=0;str[i]!=9&&str[i]!=0;i++)
;
if(str[i]==9)
{
if (DEBUG) printf("str[%d] == %d/n",i,str[i]);
 return 9;
}  else
{
if (DEBUG) printf("str[%d] == %d/n",i,str[i]);
return 0;
}
}

$ make
gcc -g -c tmp.c
tmp.c: In function 鈥榩rintfile鈥?
tmp.c:158: warning: assignment makes integer from pointer without a
cast
tmp.c:158: warning: comparison between pointer and integer
tmp.c:165: warning: assignment makes integer from pointer without a
cast
tmp.c:165: warning: comparison between pointer and integer
gcc -o tmp tmp.o -g
$ ./tmp
------------------the sick file----------------------
[0]:total 48
[1]:-rw-rw-r--  1 macg macg 3301 Jan 16
02:16   
file.c
[2]:-rw-rw-r--  1 macg
macg   52 Jan 16 02:19
Makefile
[3]:   
-rw-rw-r--  1 macg
macg            
0 Jan
16    
02:56   testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis is
a testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56
tmp.o
--------------------modify line--------------------
fri is 2,the new line is following:
[1]row:1 macg macg 3301 Jan 16 02:16 file.c
[3]row:1 macg macg 0 Jan 16 02:56 testtmp
-------------------new file-------------------------
[0]:total 48
[1]:1 macg macg 3301 Jan 16 02:16 file.c
[2]:-rw-rw-r--  1 macg
macg   52 Jan 16 02:19
Makefile
[3]:1 macg macg 0 Jan 16 02:56 testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis is
a testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56
tmp.o

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.