linux 文件读写

来源:互联网 发布:数控g76内螺纹编程实例 编辑:程序博客网 时间:2024/05/19 15:40

 

   两种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    Truncatefile 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;
}
 3int ret;
if ((ret=fclose(stream))==-1) printf("close fileerror/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  DOS0x0a   即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 rangeof data type
tmp.c:59:27: warning: character constant too long for itstype


   
   fgets字符串指针改成字符串数组,消灭了Segmentationfault错误
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("closefile 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 macgmacg   52 Jan 16 02:19Makefile
[3]:1 macg macg 0 Jan 16 02:56 testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis isa testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56tmp.oif((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 1602:16   file.c
[2]:-rw-rw-r--  1 macgmacg   52 Jan 16 02:19Makefile
[3]:   -rw-rw-r--  1 macgmacg            0 Jan16    02:56   testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis isa testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56tmp.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
recordis      -rw-rw-r--  1 macgmacg            0 Jan16    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
recordis      -rw-rw-r--  1 macgmacg            0 Jan16    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,intfrsi)-------修改文件的函数
实际是从 srcfile读出文件
把其中符合frs[j].recno的行,修改成frs[j].record
其他行不变,仍旧用srcfile读出的行
然后把这些行重新写入一个新文件tmpfile
writefile(char *tmpfilename,char*srcfilename,struct Filerecord *frs,int frsi
o    tmpfilename新文件名

o    srcfilename旧文件名

o    structFilerecord *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 fileerror/n");
if ((ret=fclose(srcstream))==-1) printf("close fileerror/n");

}   
例子:去掉文件中行的TAB键和起首空格或TAB
执行:
   读出原文件每行,checkinvaild() ,看是否含有TAB,起首空格/TAB
   如果确实有,就对此行处理,重新组合,去掉TAB,起首空格/TAB,然后写入struct person fr[20]数组
   writefile("testtmp.tmp","testtmp",fr,fri);
------------------the sickfile----------------------------------------
[0]:total 48
[1]:-rw-rw-r--  1 macg macg 3301 Jan 1602:16   file.c
[2]:-rw-rw-r--  1 macgmacg   52 Jan 16 02:19Makefile
[3]:   -rw-rw-r--  1 macgmacg            0 Jan16    02:56   testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis isa testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56tmp.o
--------------------modifyline--------------------------------------
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
-------------------newfile---------------------------------------
[0]:total 48
[1]:1 macg macg 3301 Jan 16 02:16 file.c
[2]:-rw-rw-r--  1 macgmacg   52 Jan 16 02:19Makefile
[3]:1 macg macg 0 Jan 16 02:56 testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis isa testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56tmp.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 sickfile-----------------------/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("--------------------modifyline--------------------/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 acast
tmp.c:158: warning: comparison between pointer and integer
tmp.c:165: warning: assignment makes integer from pointer without acast
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 1602:16   file.c
[2]:-rw-rw-r--  1 macgmacg   52 Jan 16 02:19Makefile
[3]:   -rw-rw-r--  1 macgmacg            0 Jan16    02:56   testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis isa testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56tmp.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 macgmacg   52 Jan 16 02:19Makefile
[3]:1 macg macg 0 Jan 16 02:56 testtmp
[4]:this is a testthis is a testthis is a testthis is a testthis isa testth
[5]:-rw-rw-r--  1 macg macg 1428 Jan 16 02:56tmp.o