2.Linux应用编程——标准IO

标准IO(库函数)


库:在用户空间
系统调用:在内核中


标准io操作的是流。


缓存区:全缓存(操作文件的时候)、行缓存(遇到\n刷新缓存区)、不缓存


缓存io是标准io库中的。
非缓存io就是文件io。


标准IO的核心对象就是流。当用标准IO打开一个文件时,就会创建一个FILE结构体描述该文
件(或者理解为创建一个FILE结构体和实际打开的文件关联起来)。我们把这个FILE结构体形象地称为流。


FILE结构体
typedef struct _IO_FILE FILE;
struct _IO_FILE {
 int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags


 /* The following pointers correspond to the C++ streambuf protocol. */
 /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
 char* _IO_read_ptr; /* Current read pointer */
 char* _IO_read_end; /* End of get area. */
 char* _IO_read_base; /* Start of putback+get area. */
 char* _IO_write_base; /* Start of put area. */
 char* _IO_write_ptr; /* Current put pointer. */
 char* _IO_write_end; /* End of put area. */
 char* _IO_buf_base; /* Start of reserve area. */
 char* _IO_buf_end; /* End of reserve area. */
 /* The following fields are used to support backing up and undo. */
 char *_IO_save_base; /* Pointer to start of non-current get area. */
 char *_IO_backup_base;  /* Pointer to first valid character of backup area */
 char *_IO_save_end; /* Pointer to end of non-current get area. */


 struct _IO_marker *_markers;


 struct _IO_FILE *_chain;


 int _fileno;
#if 0
 int _blksize;
#else
 int _flags2;
#endif
 _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */


#define __HAVE_COLUMN /* temporary */
 /* 1+column number of pbase(); 0 is unknown. */
 unsigned short _cur_column;
 signed char _vtable_offset;
 char _shortbuf[1];


 /*  char* _save_gptr;  char* _save_egptr; */


 _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};


标准I\O API
1.fopen:
#include <stdio.h>
FILE *fdopen(int fd, const char *mode);
返回值为文件指针
两个参数分别为要打开文件路径和模式
模式:
r:只读
r+:读写,从文件头开始,文件必须存在
w:只写,清空,如果不存在则创建,从文件头开始
w+:读写,清空,如果不存在则创建,从头文件开始
a:写,追加。从尾部开始,不存在则创建
a+:读写,追加,从尾部开始,不存在则创建
对应:
fopen(argv[1], “r”)   :   open(argv[1], O_RDONLY)
fopen(argv[1], “r+”)  :   open(argv[1], O_RDWR)
fopen(argv[1], “w”)   :   open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)
fopen(argv[1], “w+”)  :   open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666)
fopen(argv[1], “a”)   :   open(argv[1], O_WRONLY|O_CREAT|O_APPEND, 0666)
fopen(argv[1], “a+”)  :   open(argv[1], O_RDWR|O_CREAT|O_APPEND, 0666)


注: 
void perror(const char* s):
s:在标准错误流上输出的信息
标准IO函数执行时如果出现错误,会把错误代码保存在errno中。


2.fgetc,fputc
#include <stdio.h>
int fgetc(FILE *stream);


int fputc(int c, FILE *stream);
从fp文件流指针所指向的文件中读取一个字符返回给变量c,然后通过fputc函数将变量c的数据打印在stdout(终端)上。
char c=fclose(fp)
fputc(c,stdout);


将fp文件流指针所指向的文件中的内容依次读出打印,直到c==EOF.(EOF表示文件末尾)
while(EOF!=(c=fgetc(fp)))
{
   fputc(c,stdout);
}
注:# define EOF (-1)     可以知道EOF为-1
实例——  用fgetc和fputc实现copy
#include "stdio.h"
int main(int argc, const char *argv[])
{
char c,s;
FILE* fp1=NULL,*fp2=NULL;
if(NULL==(fp1=fopen(argv[1],"r")))
{
perror("fopen");
}
if(NULL==(fp2=fopen(argv[2],"w")))
{
perror("fopen");
}
while(EOF!=(c=fgetc(fp1)))
{
fputc(c,stdout);
}
fclose(fp1);
fclose(fp2);
return 0;
}


3.fgets
#include <stdio.h>
fgets(char* s,int size,FILE* pf1)//
描述:从pf1文件流指针所指向的文件中读取长度为size的字符串,并赋给字符串s。它会在读到EOF或者'\n'时停止。
实例:
如果一个文件的当前位置的文本如下:
Love, I Have
Since you can do it.
如果用fgets(str1,6,file1);去读取
则执行后str1 = "Love," ,读取了6-1=5个字符
这个时候再执行fgets(str1,20,file1)则执行后str1 = " I Have\n"
而如果
fgets(str1,23,file1);
则执行str1="Love ,I Have",读取了一行(包括行尾的'\n',并自动加上字符串结束符'\0'),
当前文件位置移至下一行,虽然23大于当前行上字符总和,可是不会继续到下一行。而下一
次调用 fgets()继续读取的时候是从下一行开始读。


(注:gets该函数因为没有指定s的大小,某时会导致s的溢出,所以一般不用gets)


fputs(const char* s,FILE* pf2)//将字符串s写入pf2文件流指针所指向的文件中去。
下面这个代码值打印复制10个
实例——下面代码将文件1  cp   到文件2
#include <stdio.h>
int main(int argc, const char *argv[])
{
FILE* fp1=NULL,*fp2=NULL;
char* s,*c;
if((fp1=fopen(argv[1],"r"))==NULL)
{
perror("fopen");
}
if((fp2=fopen(argv[2],"w"))==NULL)
{
perror("fopen");
}
while((c=fgets(s,10,fp1))!=NULL)
{
fputs(s,fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}


4.fread
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:存放读取数据地址的指针。
size:要读的每个数据项的字节数(当它为1时就等效于fgetc的功能)。
nmemeb:要读的数据项个数(这也是fgets所不具备的,fgets是直接读到(\n)newline和EOF)。
stream:读取文件的文件流指针。
返回值:为本次操作实际读取的元素个数(不是字节数,一般与nmemb比较),
若返回值与nmemb不相同,则可能文件结尾发生错误。如果发生错误或者达到文件结尾,返回一个短期值或者0。


5.fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);//同上
实现代码如下:
实例—— 按个将1中的内容copy  2中,检查最后每次fread的返回值
(注:检测fread的返回值的真正含义)
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char st[128];
FILE* pf1=NULL,*pf2=NULL;//注意后面一个变量也要加*
size_t flag;


if((pf1=fopen(argv[1],"r"))==NULL)
{
perror("fopen");
}
if((pf2=fopen(argv[2],"w"))==NULL)
{
perror("fpoen");
}
while((flag=fread(st,1,1,pf1))!=0)
{
printf("flag:%ld\n",flag);
fwrite(&st[0],1,1,pf2);
}
printf("flag:%ld\n",flag);
fclose(pf1);
fclose(pf2);
return 0;
}
结果:除了最后一次,也就是while外面的flag打印为0,其他都为1,之后将第二参数,也就是
读取元素类型设置为2(2字节),结果还是一样。因此,fread返回值为读到的对象个数。


6.fseek
int fseek(FILE *stream, long offset, int whence);//定位流的位置
long ftell(FILE *stream);//ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数
void rewind(FILE *stream);
实例——简单测长
#include <stdio.h>
int main(int argc, const char *argv[])
{
FILE* pf=NULL;
if(argc<2)
{
return -1;
}
if(NULL==(pf=fopen(argv[1],"r")))
{
perror("fail of fopen");
}
fseek(pf,1,SEEK_SET);
long int len=ftell(pf);
fprintf(stdout,"%ld",len);
return 0;
}


实例——循环记录系统时间
#include <stdio.h>
#include <time.h>
int main(int argc, const char *argv[])
{
FILE* pf=NULL;
time_t t=0;
struct tm* t_s=NULL;
if((pf=fopen(argv[1],"w"))==NULL)
{
perror("open");
}
while(1)
{
t=time(NULL);//得到返回值
t_s=localtime(&t);
fprintf(pf,"%d %d %d %d %d %d\n",t_s->tm_year+1900,t_s->tm_mon+1,t_s->tm_mday,t_s->tm_hour,t_s->tm_min,t_s->tm_sec); fprintf(stdout,"%d %d %d %d %d %d\n",t_s->tm_year+1900,t_s->tm_mon+1,t_s->tm_mday,t_s->tm_hour,t_s->tm_min,t_s->tm_sec);
sleep(1);
}
fclose(pf);
return 0;
}
总结:time通常的使用方法是传入NULL,返回时间值,这个值是个很大的time_t类型数据,是从计算机元年开始计算也就是1960年。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值