栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

常用的标准IO和文件IO

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

常用的标准IO和文件IO

目录
  • 一、认识IO
    • 1.IO的种类
    • 2.缓冲区
      • 2.1缓冲区的种类
      • 2.2缓冲区的刷新机制
        • 2.2.1行缓冲区的刷新机制
        • 2.2.2全缓冲区的刷新机制
    • 3.常用函数接口种类
  • 二、标准IO
    • 1.什么是FILE
    • 2.什么是错误码
    • 3.fopen / fclose
      • 3.1fopen
      • 3.2fclose
    • 4.fgetc / fputc
      • 4.1fgetc(getc,getchar)
      • 4.2fputc(putc,putchar)
    • 5.fgets / fputs
      • 5.1fgets(gets)
      • 5.2fputs(puts)
    • 6.fread / fwrite
      • 6.1fread
      • 6.2fwrite
    • 7.格式化控制相关函数
      • 7.1sprintf
      • 7.2snprintf
      • 7.3fprintf
    • 8.关于光标位置的相关函数
      • 8.1fseek
      • 8.2ftell
      • 8.3rewind
  • 三、文件IO
    • 1.什么是文件描述符
    • 2.open
    • 3.close


一、认识IO 1.IO的种类
标准IO文件IO
ANSI C (标准C库)posix (可移植操作系统的标准)
库函数系统调用

系统调用:从用户空间到内核空间的切换过程,不同的操作系统系统调用的接口是不同的。只要从用户空间到内核空间了就要发生一次系统调用,效率比较低。系统调用没有缓冲区。
库函数:库函数的平台的通用新更强,库函数有缓冲区,效率比系统调用高。库函数=缓冲区+系统调用

2.缓冲区 2.1缓冲区的种类

全缓存:和文件相关的缓冲区就是全缓存 (fp 4096字节)

行缓存:和终端相关的缓冲区是行缓存 (stdin stdout 1024字节)

不缓存:标准出错没有缓冲区(stderr 0字节)

2.2缓冲区的刷新机制 2.2.1行缓冲区的刷新机制

1.行缓存遇到’n’字符会刷新缓冲区
2.程序执行结束,也会刷新行缓冲区
3.当输入和输出发生切换的时候也会刷新缓冲区
4.当关闭文件指针的时候也会刷新缓冲区
5.fflush主动刷新缓冲区
6.如果(行)缓冲区满了,会刷新缓冲区

2.2.2全缓冲区的刷新机制

1.程序执行结束,也会刷新全缓存
2.输入输出发生切换的时候,会刷新全缓存
3.关闭文件指针,会刷新全缓存
4.fflush主动刷新缓冲区
5.全缓存满,也会刷新缓冲区

3.常用函数接口种类

标准IO:printf scanf fopen fclose fread fwrite fgetc fputc fgets fputs…

文件IO:open read write close…

二、标准IO 1.什么是FILE

标准IO库的操作依赖于流(stream)进行。打开一个文件就会创建一个FILE对象,返回一个FILE**的指针(文件指针)此对象是一个结构体。在这个结构体中记录所有的关于文件的信息,以后对文件的操作通过FILE*来完成。

/usr/include/
ctags -R //创建索引
vi -t FILE //查找FILE实现的位置

typedef struct _IO_FILE FILE;  

struct _IO_FILE {    
  char* _IO_buf_base;   //缓冲区的首地址
  char* _IO_buf_end;    //缓冲区的结束地址
   ...
};

在一个正在执行的程序中,已经创建了三个FILE的指针,如下:

stdin: 标准输入 (scanf)
stdout 标准输出 (printf)
stderr: 标准出错

2.什么是错误码

在文件IO或标准IO相关接口被调用的时候,如果出错了,操作系统会给应用程序返回错误码

#include 
char* strerror(int errnum);
功能:根据错误码转换错误信息
参数:
   @errnum:这个是错误码,包含
        #include 
         extern int errno;
返回值:错误信息字符串
    
void perror(const char *s);
功能:打印错误码对应的信息
参数:
   @s:用户附加的信息
返回值:无

strerror的使用

#include 
#include 
#include 
//extern int errno;

int main(int argc,const char * argv[])
{
    //定义文件指针
    FILE *fp;

    //以只读的方式打开文件,文件不存在会报错
    fp = fopen("./hello.txt","r");
    if(fp == NULL){
        printf("%sn",strerror(errno));
        return -1;
    }

    fclose(fp);
    return 0;
}

perror的使用

#include 

int main(int argc,const char * argv[])
{
    //定义文件指针
    FILE *fp;

    //以只读的方式打开文件,文件不存在会报错
    fp = fopen("./hello.txt","r");
    if(fp == NULL){
        perror("open hello.txt");
        return -1;
    }

    fclose(fp);
    return 0;
}
3.fopen / fclose 3.1fopen

功能:使用标准IO打开文件

#include 
FILE* fopen(const char *pathname, const char *mode);

参数:
@pathname: 路径/文件名 “./hello.txt”
@mode:打开文件的方式 “r”

 	r:以只读的方式打开文件,将文件中的光标定位在文件的开头
    r+:以读写的方式打开文件,将文件中的光标定位在文件的开头
    w:以只写的方式打开文件,如果文件不存在就创建文件,如果文件存在就清空,将光标定位在开头 
    w+:以读写的方式打开文件,如果文件不存在就创建文件,如果文件存在就清空,将光标定位在开头  
    a:以追加(结尾写)的方式打开文件,如果文件不存在就创建文件,将光标定位在文件的结尾
    a+:以读和追加(结尾写)的方式打开文件,如果文件不存在就创建文件,如果读从开头读,写在文件的结尾写

返回值:成功返回文件指针,失败返回NULL,置位错误码
实例:

#include 

int main(int argc,const char * argv[])
{
    //定义文件指针
    FILE *fp;
    //以追加的方式打开文件,如果文件存在,不会清空(追加)
    if(NULL == (fp = fopen("./hello.txt","a")))
    {
        printf("create file errorn");
        return -1;
    }

    return 0;
}
3.2fclose

功能:关闭文件

int fclose(FILE* stream);

参数:
@stream:文件指针
返回值:成功返回0,失败返回EOF(end of file),并置位错误码
实例:

#include 

int main(int argc,const char * argv[])
{
    FILE *fp;
    //以只写的方式打开文件
    fp = fopen("./hello.txt","w");
    if(fp == NULL){
        printf("create file errorn");
        return -1;
    }
    //关闭文件
    if(fclose(fp)<0){
        printf("close file errorn");
        return -1;
    }

    return 0;
}
4.fgetc / fputc 4.1fgetc(getc,getchar)

功能:从文件中读取一个字符

int fgetc(FILE *stream);

参数:
@stream:文件指针
返回值:成功返回字符的ascii,读取文件的结尾EOF,失败返回error
实例:

#include 

int main(int argc,const char * argv[])
{
    FILE *fp;
    fp = fopen("./01fopen.c","r");
    if(fp == NULL){
        perror("fopen error");
        return -1;
    }
    int i=0;
    while(i++<30){
        printf("%c",fgetc(fp));
    }
    puts("");//换行

    fclose(fp);
    return 0;
}
4.2fputc(putc,putchar)

功能:向文件中写一个字符

int fputc(int c, FILE *stream);

参数:
@c:被写字符的ascii
@stream:文件指针
返回值:成功返回ascii,失败返回EOF
实例:

#include 

int main(int argc, const char *argv[])
{
    FILE *fp;

    fp = fopen("./test.txt", "w");
    if (fp == NULL)
    {
        perror("fopen error");
        return -1;
    }

    fputc('h', fp);
    fputc('e', fp);
    fputc('l', fp);
    fputc('l', fp);
    fputc('o', fp);

    fclose(fp);
    return 0;
}
5.fgets / fputs 5.1fgets(gets)

功能:从文件指针中读取一个字符串

char *fgets(char *s, int size, FILE *stream);

参数:
@s:用来存储读取到字符的首地址
@size:读取的大小(最多读取size-1)
@stream:文件指针
返回值:成功返回s,失败返回NULL
注:遇到换行或者EOF的停止读取,换行符也会被读取到s的缓冲区中,并且在换行符之后存储一个''结束符
实例:

#include 
#include 

int main(int argc,const char * argv[])
{
    char buffer[1024];

    printf("input string > ");
    fgets(buffer,sizeof(buffer),stdin);
    
    //将读取到的换行符设置为''
    //hellon
    //buffer=hello'n'''
    //strlen(buffer)=6
    //buffer[5]=''
   buffer[strlen(buffer)-1]='';


    printf("%sn",buffer);

    return 0;
}
5.2fputs(puts)

功能:将s字符串中的内容写入到文件中

int fputs(const char *s, FILE *stream);

参数:
@s:首地址
@stream:文件指针
返回值:成功返回写入的字符的个数,失败返回EOF
实例:

#include 

int main(int argc,const char * argv[])
{
    FILE*fp;
    //向标准输出中写入字符串
    fputs("helloworld",stdout);
    //向标准出错中写入字符串
    fputs("helloworld",stderr);
   
   if ((fp = fopen("hello.txt", "w")) == NULL)
    {
        perror("fopen file error");
        return -1;
    }

    fputs("i love china",fp);

    fclose(fp);
    return 0;
}
6.fread / fwrite 6.1fread

功能:从文件中读取数据到ptr中

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

参数:
@ptr:保存读取到数据的首地址
@size:每一项的大小
@nmemb:项的个数
@stream:文件指针
返回值:成功返回读取到的项目的个数,如果是失败或者读取到的文件的结尾返回值是要小于nnemb或者0
错误还是读取到文件的结尾需要通过feof(fp)或者ferror(fp)来判断
实例:

#include 

#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)
int main(int argc,const char * argv[])
{
    FILE *fp;
    int num;

    if((fp = fopen("test.txt","r"))==NULL)
        PRINT_ERR("fopen error");

    fread(&num,4,1,fp);

    printf("read num = %dn",num);
    fclose(fp);
    return 0;
}
6.2fwrite

功能:将ptr中的数据写入到文件中

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

参数:
@ptr:数据的首地址
@size:每一项的大小
@nmemb:项的个数
@stream:文件指针
返回值:成功返回写的项目的个数,如果是失败返回值是要小于nnemb或者0
实例:

#include 

#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)
int main(int argc,const char * argv[])
{
    FILE *fp;
    int num;

    if((fp = fopen("test.txt","r"))==NULL)
        PRINT_ERR("fopen error");

    fread(&num,4,1,fp);

    printf("read num = %dn",num);
    fclose(fp);
    return 0;
}
7.格式化控制相关函数 7.1sprintf

功能:向str中进行字符串的格式化

int sprintf(char *str, const char *format, ...);

参数:
@str:首地址
@format:控制格式
返回值:成功返回成功格式化字符的个数,失败返回负数

char s[50];
sprintf(s,"%4d-%02d-%02d %02d:%02d:%02dn",tm->tm_year+1900,
    tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
//把双引号中的字符串存放在s的数组中
    //s="2022-4-26 17:30:20"
fputs(s,fp); //将s中的字符串写入到文件中

注:当使用sprintf往数组中写入字符的时候,如果出现越界,虽然编译的时候会提示警告,但是在程序运行的时候有多少字符就格式化多少字符,这个内存越界的错误仍然会出现

7.2snprintf

功能:将字符串格式化到str的数组中

int snprintf(char *str, size_t size, const char *format, ...);

参数:
@str:存放格式化后的字符串的内存首地址
@size:大小(字符size-1)
@format:格式化的控制格式
返回值:成功返回字符的个数,失败返回负数

#include 

int main(int argc,const char * argv[])
{
    char s[10];

    snprintf(s,sizeof(s),"%s","helloworld1234");
    printf("s = %sn",s);
    //上输入的字符个数大于s的大小的时候,最多格式化sizeof(s)-1个字符,在s最后一个字符的
    //位置补上''
    return 0;
}
7.3fprintf

功能:将格式化后的字符串向对应的文件指针中输出

int fprintf(FILE *stream, const char *format, ...);

参数:
@stream:文件指针
@format:控制格式
返回值:成功返回**>0**,失败返回**<0**

8.关于光标位置的相关函数 8.1fseek

功能:修改光标的位置

int fseek(FILE *stream, long offset, int whence);

参数:
@stream:文件指针
@offset:偏移
>0 向后偏移 =0 不偏移 <0 向前偏移
@whence:
SEEK_SET,开头 SEEK_CUR,当前位置 SEEK_END,结尾
返回值:成功返回0,失败返回 -1 ,置位错误码
实例:

	fseek(fp,0,SEEK_SET);将光标定位在文件的开头
	fseek(fp,10,SEEK_SET);从文件的开头向后偏移10个字节
	fseek(fp,10,SEEK_CUR);从光标当前位置向后偏移10个字节
	fseek(fp,-10,SEEK_END);从文件结尾向前偏移10个字节
	fseek(fp,0,SEEK_END);将光标定位在文件结尾          
8.2ftell

功能:获取光标当前的位置

long ftell(FILE *stream)

参数:
@stream:文件指针
返回值:成功返回光标的位置,失败返回 -1 ,置位错误码
实例:

fseek(fp,0,SEEK_END); 
ftell(fp);   ===>功能统计文件所占用的字符的个数(大小)
8.3rewind

功能:恢复光标的位置到文件的开头

void rewind(FILE *stream);

参数:
@stream:文件指针
返回值:无
实例:

 rewind(fp) == fseek(fp,0,SEEK_SET)  等价
三、文件IO

文件IO:是通过系统调用实现的,只要调用文件IO的函数接口就会从用户空间进入到内核空间,系统调用的效率比较低,因为没有缓冲区的概念。
文件IO常见的接口有open,read,write,close,lseek等

1.什么是文件描述符

文件描述符:文件描述符本身是一个大于等于0的整数,使用open打开文件之后返回文件描述符,以后在操作文件的时候通过这个文件描述符完成。在一个正在执行的程序中文件描述符的范围是0-1023(1024个),可以通过ulimit -a查看限制,这个限制值是可以修改的(ulimit -n 2048)。文件描述符的分配原则是最小未使用。在一个正在执行的程序中默认已经有三个文件描述符了。
0:标准输入文件描述符

1:标准输出文件描述符

2:标准错误文件描述符

ulimit -a

real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 0
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 15294
max locked memory           (kbytes, -l) 498056
max memory size             (kbytes, -m) unlimited
open files                          (-n) 1048576
pipe size                (512 bytes, -p) 8
POSIX message queues         (bytes, -q) 819200
real-time priority                  (-r) 0
stack size                  (kbytes, -s) 8192
cpu time                   (seconds, -t) unlimited
max user processes                  (-u) 15294
virtual memory              (kbytes, -v) unlimited
file locks                          (-x) unlimited

注:在标准IO的文件指针结构体中其实默认包含文件描述符_fileno

#include 

int main(int argc,const char * argv[])
{
    printf("%dn",stdin->_fileno); //标准输入文件描述符 0
    printf("%dn",stdout->_fileno); //标准输出文件描述符 1
    printf("%dn",stderr->_fileno); //标准出错文件描述符 2
    return 0;
}
2.open

功能:打开文件

#include 
#include 
#include 

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

参数:
@pathname:文件的路径和文件的名字
@flags:文件的打开方式
@mode:只有在第二个flags参数写O_CREAT的时候才需要填充,第三个参数代表创建文件的权限

		O_RDONLY,  只读的方式打开文件
		O_WRONLY,  只写的方式打开文件
		O_RDWR.    读写的方式打开文件
        O_APPEND   以追加的方式打开文件
        O_CREAT    创建文件,必须填写第三个参数,第三个参数代表创建这个文件的权限
        O_TRUNC    清空文件
        O_EXCL     确保文件存在,跟O_CREAT结合使用,如果文件存在就返回EEXIST已存在错误,
 如果文件不存在正常创建
 实际创建文件权限:mode & (~umask)   umask的值0002            umask 0000
        			               ~umask=0664               ~umask=0666
 文件的最大权限是0666                 mode & 0664           mode & 0666

返回值:成功返回文件描述符,失败返回 -1 置位错误码

标准IO文件IO含义
“r”O_RDONLY只读的方式打开文件
“r+”O_RDWR以读写的方式打开文件
“w”O_WRONLY|O_CREAT|O_TRUNC, 0664以只写的方式打开文件,如果文件存在就清空,如果文件不存在就创建
“w+”O_RDWR|O_CREAT|O_TRUNC,0664以读写的方式打开文件,如果文件存在就清空,如果文件不存在就创建
“a”O_WRONLY|O_APPEND|O_CREAT,0664以追加(结尾写)的方式打开文件,如果文件不存在就创建文件
“a+”O_RDWR|O_APPEND|O_CREAT,0664以追加(结尾写,开头读)的方式打开文件,如果文件不存在就创建文件
#include 
#include 
#include 
#include 
#include 
#include 
#include 
                                                                                           
#define PRINT_ERR(msg) do{ 
        perror(msg);
        return -1;
    }while(0)
    
int main(int argc, const char *argv[])
{
    int fd;
    //读写的方式打开文件,如果文件不存在就创建文件
    //如果文件存在就报文件已存在的错误EEXIST
    fd = open("hello.c", O_RDWR | O_CREAT | O_EXCL, 0666);
    if (fd == -1)
    {
        if (errno == EEXIST)
        {
            //文件已经存在,不需要创建,直接打开
            printf("文件已经存在,不需要创建,直接打开n");
            fd = open("hello.c", O_RDWR, 0666);
        }
        else
        {
            PRINT_ERR("open error");
        }
    }

    return 0;
}
3.close

功能:关闭文件

#include 
int close(int fd);

参数:
@fd:文件描述符
返回值:成功返回0,失败返回 -1置位错误码

#include 

int main(int argc, const char *argv[])
{
    int fd;
    //读写的方式打开文件,如果文件不存在就创建文件
    //如果文件存在就报文件已存在的错误EEXIST
    fd = open("hello.c", O_RDWR | O_CREAT | O_EXCL, 0666);
    if (fd == -1)
    {
        if (errno == EEXIST)
        {
            //文件已经存在,不需要创建,直接打开
            printf("文件已经存在,不需要创建,直接打开n");
            fd = open("hello.c", O_RDWR, 0666);
        }
        else
        {
            PRINT_ERR("open error");
        }
    }
  printf("fd = %dn",fd);  //这里的fd是3
    
    //每一个正在执行的程序都有0-1023这1024个文件描述符
    //关闭这个程序中的文件描述符,不影响其他程序的文件描述符。
    close(fd);
    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/847777.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号