请选择 进入手机版 | 继续访问电脑版
查看: 179|回复: 2

[单片机资料] Linux学习之标准IO教程

[复制链接]

签到天数: 395 天

[LV.9]元老将成

发表于 2018-9-14 21:26:34 | 显示全部楼层 |阅读模式
标准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年。

签到天数: 678 天

[LV.9]元老将成

发表于 2018-9-15 10:29:06 | 显示全部楼层
不错的文章
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

返回顶部