您的位置:首页 > 运维架构 > Linux

linux 文件读写

2009-09-07 17:32 471 查看
两种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; 注意类型是大写
2if((stream=fopen("testtmp","r+"))==NULL)

{ printf("open file error/n");

return;

}

3int 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的换行符的区别

linuxDOS
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'

几个常见特殊字符的整型数字

charint
空格' '

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: