• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

XiaoXiaoli

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

c_标准IO

关于IO有两种,其中一个是标准IO,另一个是系统调用IO。IO操作是一切实现的基础,比如说程序产生的数据我们将其转移到文件中保留。

标准IO和系统调用IO我们优先使用标准IO。不同系统会提供一套自己的系统调用IO,如Linux系统和Windows系统会分别提供一套IO提供给程序员使用。标准IO提供一套标准的IO和系统内核对话,标准IO依赖于系统IO实现。如我们常见的sprintf函数,我们在使用时,不会注意到是哪个操作系统,我们直接就使用了,不管在Linux或windows我们都可以使用,如fopen在linux依赖于open,在windows依赖于openfile。标准IO的可移植性较好。

标准IO,FILE的类型结构体贯穿整个标准IO。该结构体中的字段中有操作文件必须要的属性和数据。

目录

文件打开 - fopen

文件关闭 - fclose

文件读写操作

  字符读写-fgetc、fputc

  字符串读写-

  二进制读写-

  二进制数据块读写-fread、fwrite

  fprintf、fscanf

文件结束标志 EOF、feof

文件位置指针操作  -  fseek、ftell、rewind

合并系统调用 fflush。

文件打开 - fopen

fopen, fdopen, freopen - stream open functions
#include <stdio.h> FILE *fopen(const char *path, const char *mode);

 fopen函数有两个参数,path、mode。path是文件的路径、mode是文件的操作权限(可读、可写、可读写)。这两个参数都是常量指针,也就是说在函数内部不会改变传入参数的值。

mode参数的选项,6个分别为r、r+、w、w+、a、a+。写文件有两种方式,一种是以覆盖式的写入数据,一种是以追加的方式写入数据。

r      Open text file for reading.  The stream is positioned at the beginning of the file.
r,打开的文件,只是读取文件中的数据。文件的位置指针,定位于文件的开始处。 r
+ Open for reading and writing. The stream is positioned at the beginning of the file.
r+,打开的文件,可以读取文件中的数据,可以往文件写数据。 w Truncate file to zero length or create text file
for writing. The stream is positioned at the beginning of the file.
w,打开的文件,可以往文件中写入数据。如果打开的文件已存在,那么会覆盖文件中原来的数据。如果文件不存在,那么会创建一个新文件(有则清空,无则创建)。 w
+ Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
w+,打开的文件,可以往文件中写入数据也可以从文件中读取数据。如果文件不存在,那么会创建一个新文件。如果文件已经存在,往文件中写数据会覆盖原来文件中的数据(有则清空,无则创建)。 a Open
for appending (writing at end of file). The file is created if it does not exist. The stream is positioned at the end of the file.
a,打开的文件,可以往文件中写入数据,这里往文件中写入数据是追加的方式写入。如果文件不存在,那么会创建一个新文件。 a
+ Open for reading and appending (writing at end of file). The file is created if it does not exist. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.
a+,打开的文件,可以往文件中写入数据,也可以从文件中读取数据。这里写入数据也是以追加的方式写入。如果文件不存在那么会创建一个新文件。

这里创建的文件权限的公式为 0666 & ~umask,umask存在的机制就是怕文件的权限过低,umask过高,消掉的权限就越多。

 返回值,函数执行成功时返回一个FILE*。函数执行失败时,返回一个NULL指针并设置errorno。

关于errorno,errorno是一个全局变量(大家一起使用),出错时如果不马上打印,可能会被别人的出错覆盖。

关于函数返回值,我们使用时定义一个FILE* 来接收,那么此时思考一个问题,该指针指向的位置在哪呢?栈、静态区、堆?答案是堆。

 

 

 计算机编程中有三个规则,谁打开谁关闭、谁申请谁释放、是资源就有上限。是资源就有上限,那么一个进程调用fopen能打开的文件上限是多少呢?一个进程默认打开三个流(标准输入stdin、标准输出stdout、标准错误stderr,这三个流的输出都是标准输出设备-显示器),进程一共可以打开1024个文件。可以使用ulimit命令改变进程的最大打开文件个数。

 

文件读写操作

字符读写_fgetc

fgetc,从文件中读出数据到应用程序。

#include <stdio.h>
int fgetc(FILE *stream);
fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.

fgetc的参数,文件的指针。

fgetc的返回值,函数执行成功返回的是读到的字符的整型值,函数执行失败返回的是EOF。如果读到文件的结尾,返回EOF。

代码1,使用fgetc函数读取文件的一个字符。

#include <stdio.h>
#include <stdlib.h>

 int main(int argc, char *argv[]){
    FILE *fp = NULL;
    fp = fopen("./demo.txt", "r");
    if(fp == NULL){
      perror("fopen error!!!");
      return -1;
    }

    char c = fgetc(fp);
    printf("c = %c\n", c);

    fclose(fp);
    return 0;
}

文件内容和程序的执行结果。

 代码2,当我们知道了文本文件的结束标志是-1时,使用循环读取整个文本文件的内容。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
        FILE *fp = NULL;
        fp = fopen("./demo.txt", "r");
        if(fp == NULL){
                perror("fopen error!!!");
                return -1;
        }

        char c = 0;
        while ((c = fgetc(fp)) != -1) {
                printf("%c", c);
        }
        fclose(fp);
        return 0;
}

文件中的内容和程序执行的结果。

 

代码3,从文件中读取数据,将数据保存到字符数组中。将数据存储在字符数组中的目的,方便我们后续对字符串的处理。

int main(int argc, char *argv[]){
        FILE *fp = NULL;
        fp = fopen("./demo.txt", "r");
        if(fp == NULL){
                perror("fopen error!!!");
                return -1;
        }

        char file_c[256] = { 0 };
        int i = 0;
        while ((file_c[i] = fgetc(fp)) != EOF) {
                i++;
        }
        printf("%s", file_c);
        fclose(fp);
        return 0;
}

 文件字符读写_fputc

fputc将应用程序的数据写入到文件中。

fputc, fputs, putc, putchar, puts - output of characters and strings
#include <stdio.h>

int putc(int c, FILE *stream);

fputc() writes the character c, cast to an unsigned char, to stream.
fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.

函数参数两个,第一个为写入文件的字符,第二个为文件。

返回值,函数执行成功返回的时写入的字符的整型数,函数执行失败返回的是EOF。

 代码1,将一个字符串通过fputc函数写入到文件中。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

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

    char* s = "hello world";
    int i = 0;
    for (i = 0; i < strlen(s);i++) {
        fputc(s[i], fp);
    }
}

fprintf,fscanf

#include <stdio.h>

int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
...输出项,将输出项按照一定的格式输出到指定的流中去。该流可以是任何打开的文件。
int sscanf(const char *str, const char *format, ...);

 

 

 

文件结束标志

文本文件的结束标志为-1,在系统中文本文件的标志定义为EOF,所以我们判断一个文件的结尾时,使用EOF。使用代码验证文本文件的结束标志为-1,代码实例如下。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
        FILE *fp = NULL;
        fp = fopen("./demo.txt", "r");
        if(fp == NULL){
                perror("fopen error!!!");
                return -1;
        }

        char c = fgetc(fp);
        printf("c = %d\n", c);
        c = fgetc(fp);
        printf("c = %d\n", c);
        c = fgetc(fp);
        printf("c = %d\n", c);

        fclose(fp);
        return 0;
}

(这段代码的基本逻辑是,文本文件中只有2个英文字符,使用fgetc读取3次,那么最后一次读取的字符就是文件的结尾。目前有一个问题就是,相同的代码在Linux平台和Windows平台下的执行结果不同)

文件的内容、Linux系统和Windows系统下执行的结果。

feof函数用来判断一个文件是否到了结尾。

clearerr, feof, ferror, fileno - check and reset stream status
#include <stdio.h>
int feof(FILE *stream);

The function feof() tests the end-of-file indicator for the stream pointed to by stream, returning nonzero if it is set. The end-of-file indicator can be
cleared only by the function clearerr().

参数文件指针。

返回值,没有到文件结尾返回0,到了文件结尾非0值。

代码1,使用feof函数判断是否到了文件结尾。这段代码最后写入buf中的数据会多出一个-1,原因是文件结束标志-1也读取并写入了。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

        FILE* fp = NULL;
        fp = fopen("./demo.txt", "r");
        if (fp == NULL) {
                perror("fopen error!!!");
                return -1;
        }
        int i = 0;
        char buf[256] = {0};
        while(!feof(fp)){
                int ch = fgetc(fp);
                buf[i] = ch;
                i++;
        }
        printf("%s", buf);

        return 0;

}

代码2,使用feof函数采用先读后判断,buf中的数据不会被写入-1。

 

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

        FILE* fp = NULL;
        fp = fopen("./demo.txt", "r");
        if (fp == NULL) {
                perror("fopen error!!!");
                return -1;
        }
        int i = 0;
        char buf[256] = {0};
        while(1){
                int ch = fgetc(fp);

           if (feof(fp)) {
            break;
           }

          buf[i] = ch;
                i++;
          
        }
        printf("%s", buf);
        return 0;

}

读入-1和没有-1的输出结果。

 

 

二进制数据块读写:fread、fwrite。

什么情况下使用这两个函数呢?

这两个函数的原型:

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

fread函数很明显,其功能为读取数据。从哪个地方读取数据呢?函数中的最后一个参数 FILE* stream。读取多少内容呢?第3个参数和第2个参数相乘,得到的结果数就是读取数据的总大小。读取到的数据又放到什么地址中呢?函数的第一个参数,void *ptr。

fwrite函数为写数据到文件中。那么写到文件中的数据在哪呢?函数的第一个参数就是写入文件的数据,const void *ptr。写入的文件大小呢?就是第2个参数和第3个参数相乘的结果。数据写到哪呢?写入到第4个参数,FILE *stream。

这两个函数的返回值:成功读到或写入成功的对象的个数。

举例:

fread(str, 1, 10, fp);

fread(str, 10, 1, fp);

这两种写法含义完全不同,如第一种写法的含义是:从fp中读取数据,一共有10个对象每个对象1个字节,数据读到str中。第二种含义为:从fp中读取数据,一个有1个对象该对象的大小为10个字节,数据读入到str中。

 

posted on 2020-12-19 14:14  XiaoXiaoli  阅读(200)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3