2023/8/15 -- IO

作业:

 

1、将课堂程序重新敲一遍

2、使用fgets完成求一个文件的行号

3、使用fgets、fputs完成两个文件的拷贝

#include 
#include 
#include 

int main(int argc, const char *argv[])
{
#if 0
	//行号
	FILE *fp;
	if(argc != 2){
		printf("input error!\n");
		printf("usage:./a.out filename");
		return -1;
	}
	if((fp = fopen(argv[1],"r")) == NULL){
		perror("fopen error");
		return -1;
	}
	char s[256];
	int count = 0;
	while(fgets(s,sizeof(s),fp) != NULL){
		count++;
	}
	printf("该文件的行数:%d\n",count);
	fclose(fp);
#endif

#if 1
	//拷贝
	FILE *srcfp;
	FILE *dstfp;
	if(argc != 3){
		printf("input error!\n");
		printf("usage:./a.out srcfilename dstfilename");
		return -1;	
	}
	if((srcfp = fopen(argv[1],"r")) == NULL){
		perror("srcfopen error");
		return -1;
	}
	if((dstfp = fopen(argv[2],"w")) == NULL){
		perror("dstfopen error");
		return -1;
	}
	char s[256];
	while(fgets(s,sizeof(s),srcfp) != NULL){
		fputs(s,dstfp);
	}
    fclose(srcfp);
    fclose(dstfp);
	printf("拷贝成功\n");
#endif
	return 0;
}

2023/8/15 -- IO_第1张图片

4、思维导图

一、IO基础知识

1.1 最先接触的IO知识

stdio.h :标准的输入输出头文件

该头文件包含的函数:scanf、printf、putchar、getchar、puts、gets

input:通过终端向程序输入数据

output:通过程序向终端输出数据

1.2 IO的分类

1> 标准的输入输出:库函数实现

2> 非标准IO(文件IO):系统调用

1.3 系统调用和库函数的区别

1> 系统调用:内核空间提供的函数,每次进行系统调用,程序都会从用户空间向内核空间进行一次切换,频繁进行系统调用,会导致程序执行效率低

例如:一个文本编辑器,如果使用系统调用,那么就是没输入一个字,就进行一次系统调用

2> 标准IO:使用的是程序库中的函数,会给输入输出一个缓冲区,当缓冲区刷新时,才会将输入或输出的数据整体进行一次系统调用,效率较高

标准IO = 缓冲区 + 文件IO

例如:一个文本编辑器,使用标准IO,会将用户输入的数据,全部先写入一个缓冲区中,当用户保存时,同一将数据调用系统调用函数,写入文件中。

2023/8/15 -- IO_第2张图片

1.4 常用的标准IO和系统调用

1> 标准IO:

printf、scanf、putchar、getchar、puts、gets --> 对终端进行输入输出

fopen、fputc、fgetc、fputs、fgets、fprintf、fscanf、fread、fwrite、fclose、fseek ---> 对文件进行输入输出操作

2> 文件IO

open、read、write、close。。。

二、标准IO

2023/8/15 -- IO_第3张图片

2.1 文件结构体类型(FILE)

1> 关于ctags的使用

作用:追代码使用

使用方式:

1、在指定目录下,使用指令ctags -R 创建一个索引文件

2、输入指令:vi -t 要查询的名字

3、可以使用ctrl + ]: 继续往后追,使用ctrl+[ :回退

2> 追FILE结构体的步骤:

1、进入根目录的usr目录中的include目录下

2、使用指令:ctags -R 创建索引文件

3、输入指令:vi -t FILE 开始追该结构体

struct _IO_FILE {                                                                                                                          


257   char* _IO_buf_base;   /* 缓冲区开始位置 */
258   char* _IO_buf_end;    /* 缓冲区结束位置 */


267 
268   int _fileno;         //文件描述符
   }

2.2 特殊的文件指针

特殊的原因:当一个进程启动时,系统会自动定义这三个指针,以便使用,也就是说,这三个指针,无需定义,直接使用即可

1> stdin:标准输入文件指针(scanf) ---->对应的文件描述符:0

2> stdout:标准输出指针(printf) ---->对应的文件描述符:1

3> stderr:标准出错指针 ---->对应的文件描述符:2

2.3 fopen的使用

       #include 

       FILE *fopen(const char *pathname, const char *mode);
功能:打开给定路径的文件,以mode的形式打开
参数1: 要打开的文件的路径,是一个字符串
参数2:打开文件时的打开方式,是一个字符串
       r      以只读的形式打开一个文件,文件指针定位在开头
               Open text file for reading.  The stream is positioned at the beginning of the file.

       r+     以读写的形式打开一个文件,文件指针定位在开头
               Open for reading and writing.  The stream is positioned at the beginning of the file.

       w      以只写的形式打开文件,如果文件不存在则创建文件,如果文件存在则清空文件内容,文件指针定位在开头
               Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.

       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.

       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+     以读或追加的形式打开文件,如果文件不存在,则创建文件,读指针定位在开头,写指针定位在结尾
               Open for reading and appending (writing at end of file).  The file is created if it does not exist.  The initial  file  posi‐
              tion for reading is at the beginning of the file, but output is always appended to the end of the file.
返回值:成功打开文件,返回该文件的地址,失败返回NULL,并置位错误码                            

2.4 关闭文件(fclose)

       #include 

       int fclose(FILE *stream);
功能:刷新文件缓冲区,并关闭文件描述符
参数:要关闭的文件指针
返回值:成功返回0,失败返回EOF并置位错误码
#include

int main(int argc, const char *argv[])
{
    FILE *fp = NULL;        //定义一个文件指针
    //fp = fopen("./01test.txt", "r");    //以只读的形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "r+");    //以读写的形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "w");    //以只写形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "w+");    //以读写的形式打开当前目录下的一个文件
    fp = fopen("./01test.txt", "a");    //以读的形式打开当前目录下的一个文件
    if(NULL == fp)
    {
        printf("文件打开失败\n");
        return -1;
    }else
    {
        printf("文件打开成功\n");
    }


    fclose(fp);          //关闭fp指针打开的文件

    return 0;
}

2.5 关于错误码的问题

2023/8/15 -- IO_第4张图片

1>概念

错误码是在文件IO或标准IO调用相关接口函数时,如果出现错误,那么内核层就会向用户层传递一个错误信息,每个错误码对应的错误信息不同

2> 错误码的种类
 
  5 #define EPERM        1  /* Operation not permitted */
  6 #define ENOENT       2  /* No such file or directory */
  7 #define ESRCH        3  /* No such process */
  8 #define EINTR        4  /* Interrupted system call */
  9 #define EIO      5  /* I/O error */
 10 #define ENXIO        6  /* No such device or address */
 11 #define E2BIG        7  /* Argument list too long */
 12 #define ENOEXEC      8  /* Exec format error */
 13 #define EBADF        9  /* Bad file number */
 14 #define ECHILD      10  /* No child processes */
 15 #define EAGAIN      11  /* Try again */
 16 #define ENOMEM      12  /* Out of memory */
 17 #define EACCES      13  /* Permission denied */
 18 #define EFAULT      14  /* Bad address */
 19 #define ENOTBLK     15  /* Block device required */
 20 #define EBUSY       16  /* Device or resource busy */
 21 #define EEXIST      17  /* File exists */                                                                                                              
 22 #define EXDEV       18  /* Cross-device link */
 23 #define ENODEV      19  /* No such device */
 24 #define ENOTDIR     20  /* Not a directory */
 25 #define EISDIR      21  /* Is a directory */
 26 #define EINVAL      22  /* Invalid argument */
 27 #define ENFILE      23  /* File table overflow */
 28 #define EMFILE      24  /* Too many open files */
 29 #define ENOTTY      25  /* Not a typewriter */
 30 #define ETXTBSY     26  /* Text file busy */
 31 #define EFBIG       27  /* File too large */
 32 #define ENOSPC      28  /* No space left on device */
 33 #define ESPIPE      29  /* Illegal seek */
 34 #define EROFS       30  /* Read-only file system */
 35 #define EMLINK      31  /* Too many links */
 36 #define EPIPE       32  /* Broken pipe */
3> 处理错误码的两个函数
       #include 

       char *strerror(int errnum);
功能:将给定的错误码,转变成对应的字符串信息
参数:错误码
返回值:成功返回错误码的信息,失败返回“Unknown error
 nnn”
注意:这里面用到了errno,该错误码定义在:#include头文件中

       #include 

       void perror(const char *s);
功能:当错误码更新时,可以使用该函数,该函数会将错误码信息输出,并附上一个提示信息s,自动换行
参数:提示信息,是一个字符串
返回值:无
4> 测试案例
#include
#include
#include       //strerror函数对应的头文件

int main(int argc, const char *argv[])
{
    FILE *fp = NULL;        //定义一个文件指针
    fp = fopen("./01test.txt", "r");    //以只读的形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "r+");    //以读写的形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "w");    //以只写形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "w+");    //以读写的形式打开当前目录下的一个文件
    //fp = fopen("./01test.txt", "a");    //以读的形式打开当前目录下的一个文件
    if(NULL == fp)
    {/*
        printf("文件打开失败\n");
        printf("%d\n", errno);
        printf("%s\n", strerror(errno));     //输出错误码对应的错误信息
        */
        
        perror("fopen error");        //无需加冒号,自动换行
                                //fopen error:No such file or directory

        return -1;
    }else
    {
        printf("文件打开成功\n");
        printf("%d\n", errno);
        printf("%s\n", strerror(errno));     //输出错误码对应的错误信息
    }


    fclose(fp);          //关闭fp指针打开的文件

    return 0;
}

  效果图
ubuntu@ubuntu:~/23062IO/day1$ ./a.out 
fopen error: No such file or directory

2.6 字符的输入输出(fgetc、fputc)

1> fputc函数

       #include 

       int fputc(int c, FILE *stream);   //fputc('H', fp)
功能:将给定的字符,写入到指定的文件中去
参数1:要写入的字符,以unsigned char形式写入
参数2:要写入的文件
返回值:成功返回写入的字符的ascii值,失败返回EOF

2> fputc函数的案例

#include

int main(int argc, const char *argv[])
{
    //定义文件指针并打开文件
    FILE *fp;
    //以写的形式打开文件
    if((fp = fopen("./01test.txt", "w")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //将数据写入文件
    fputc('H', fp);
    fputc('e', fp);
    fputc('l', fp);
    fputc('l', fp);
    fputc('o', fp);
    fputc('\n', fp);



    //关闭文件
    fclose(fp);

    return 0;
}

效果图

3> fgetc函数

       #include 

       int fgetc(FILE *stream);
功能:从给定的文件中,摘取一个字符数据
参数:文件指针
返回值:成功返回摘取的字符,失败返回或者读取到文件末尾都返回EOF

4> fgetc函数案例

#include

int main(int argc, const char *argv[])
{
    //定义文件指针并打开文件
    FILE *fp;
    //以写的形式打开文件
    if((fp = fopen("./01test.txt", "r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //从文件中读取数据
    char buf;
    while(1)
    {
        //从文件中读取一个字符
        buf = fgetc(fp);

        //对读取的字符进行判断
        if(buf == EOF)
        {
            break;
        }
        printf("%c\t", buf);
    }



    //关闭文件
    fclose(fp);

    return 0;
}

效果图

2.7 字符串输入输出(fgets、fputs)

1> 字符串输出函数:fputs

       #include 



       int fputs(const char *s, FILE *stream);
功能:将指定的字符串,输出到指定的文件中
参数1:要输出的字符串
参数2:要被写入的文件指针
返回值:成功返回写入文件中字符的个数,失败返回EOF

2> 字符串输入函数:fgets

       #include 



       char *fgets(char *s, int size, FILE *stream);
功能:从stream指针指向的文件中读取最多长度为size-1的字符串,放入数组s中
参数1:字符串容器
参数2:读取的长度:最多为size-1,如果遇到新的一行或者EOF会结束一次读取,并且会将换行作为字符放入数组中,并在最后放入字符串结束标志'\0'
参数3:文件指针
返回值:成功返回读取的字符串的地址,失败返回NULL

3> 案例

#include

int main(int argc, const char *argv[])
{
    //定义文件指针
    FILE *fp;
    //以只写的形式打开文件
    if((fp=fopen("./08test.txt", "w+")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //向文件中写入一个字符串
    fputs("Good Good Study\n", fp);
    fputs("Day Day Up\n", fp);

    //关闭文件
    fclose(fp);

    //以只读的形式打开文件
    if((fp=fopen("./08test.txt", "r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //定义一个buf
    char buf[5];
    while(fgets(buf, sizeof(buf), fp) != NULL)
    {
        printf("%s", buf);
        printf("111111111111111111111111111\n");
    }
    //关闭文件
    fclose(fp);

    return 0;
}

效果图

2023/8/15 -- IO_第5张图片

2.8 关于缓冲区大小问题

1> 行缓存:和终端相关的文件的缓冲区(stdin、stdout),大小为1024字节

2> 全缓存:和文件操作相关的文件缓冲区(fp),大小为4096字节

3> 不缓存:和出错相关的文件缓冲区,是没有缓冲区的(stderr),大小为0

#include

int main(int argc, const char *argv[])
{
    int num;
    scanf("%d", &num);

    //验证行缓存的大小
    printf("%ld\n", stdin->_IO_buf_end - stdin->_IO_buf_base);   //1024
    printf("%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base); //1024

    //验证全缓存的大小
    FILE *fp;
    if((fp=fopen("./01test.c", "r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    fgetc(fp);        //从文件中读取一个字符

    printf("%ld\n", fp->_IO_buf_end - fp->_IO_buf_base);   //4096
    fclose(fp);

    //验证无缓存的大小
    fputs("Hello world\n", stderr);
    printf("%ld\n", stderr->_IO_buf_end - stderr->_IO_buf_base);   //1
    //printf("%ld\n", BUFSIZ);   //1
    



    return 0;
}

2.9 缓冲区刷新时机

1> 行缓存的刷新时机
  • 遇到'\n'换行会自动刷新缓冲区
  • 当程序结束时,会自动刷新缓冲区
  • 当输入输出发生切换时会刷新行缓存
  • 当关闭文件指针时,会刷新行缓存
  • 当缓存区满了后,会刷新行缓存
  • 当使用fflush函数刷新缓冲区时,会刷新
       #include 

       int fflush(FILE *stream);
功能:刷新给定的文件指针的缓冲区
参数:文件指针
返回值:成功返回0,失败返回EOF并置位错误码
2> 全缓存的刷新时机
  • 遇到'\n'换行不会自动刷新全缓冲区
  • 当程序结束时,会自动刷新缓冲区
  • 当输入输出发生切换时会刷新全缓存
  • 当关闭文件指针时,会刷新全缓存
  • 当缓存区满了后,会刷新全缓存
  • 当使用fflush函数刷新缓冲区时,会刷新

2.10 对文件的格式化输入输出(fprintf、fscanf)

       #include 

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

功能:向指定文件stream中输出一个格式串
参数1:要被输出的文件指针
参数2:要输出的格式串,里面可以有%d、%c、%s...
参数3:可变参数,输出项数据,参数个数由格式串中的格式控制符决定
返回值:成功返回已经输出的字符个数,失败返回一个负数

    int fscanf(FILE *stream, const char *format, ...);
功能:从指定的文件中,读取格式数据,放入容器中
参数1:要被读取的文件指针
参数2:格式串
参数3:输入项地址列表,参数个数由格式串中的格式控制符决定
返回值:成功返回输入的项数的个数,失败返回EOF并置位错误码

2.11 sprintf、snprintf

       int sprintf(char *str, const char *format, ...);
功能:在给定的字符数组str中,存入一个格式串      
参数1:字符数组容器
参数2:格式串,可以包含格式控制符
参数3:可变参数,参数个数由格式串中的格式控制符决定
返回值:成功返回转变的字符个数,失败返回一个负数
        
       int snprintf(char *str, size_t size, const char *format, ...);
功能:将格式串放入的字符数组中,长度最多为size,并且包含字符串的结束标志'\0'
参数1:字符数组
参数2:转变的长度
参数3:格式串
参数4:可变参数
返回值:   成功返回转变的字符个数,失败返回一个负数                  

2.12 关于系统时间的函数

       #include 

       time_t time(time_t *tloc);
功能:获取系统当前的时间,得到的是从1970年1月1日0时0分0秒以来的秒数
参数:是一个时间的指针,可以传入一个NULL,则通过函数返回值得到秒数
        也可是time_t类型的变量的地址,通过函数调用,会得到当前系统时间
            调用方式:
                    time_t sysTime;    //定义变量存储时间
                    time(&sysTime);          //调用方式1
                    sysTime = time(NULL);     //调用方式2
返回值:系统时间的秒数

    struct tm *localtime(const time_t *timep);
功能:将系统时间的毫秒数,转变成时间的结构体变量
参数:系统时间的毫秒数,地址传递
返回值:时间的结构体
      struct tm {
               int tm_sec;    /* 秒数 */
               int tm_min;    /*分钟 */
               int tm_hour;   /* 小时 */
               int tm_mday;   /* 月中天数,从1开始 */
               int tm_mon;    /* 月份,从0开始 */
               int tm_year;   /* 年份+1900 */
               int tm_wday;   /* 周中的天数 */
               int tm_yday;   /* 年中的天数 */
               int tm_isdst;  /* 夏令时 */
           };
            

2.13 使用文件操作完成注册和登录功能

#include

/*********************定义注册函数******************/
void registe()
{
    char zczh[20];      //注册账号
    char zcmm[20];      //注册密码

    printf("请输入注册账号:");
    scanf("%s", zczh);
    printf("请输入注册密码:");
    scanf("%s", zcmm);

    //将注册账号和密码写入文件中
    FILE *fp;
    if((fp=fopen("./password.txt", "a")) == NULL)
    {
        perror("fopen error");
        return;
    }

    //将账号和密码写入文件中
    fprintf(fp, "%s %s\n", zczh, zcmm);

    //关闭文件
    fclose(fp);

    printf("注册成功\n");
}

/*******************登录函数*************************/
void login()
{
    char dlzh[20];      //登录账号
    char dlmm[20];        //登录密码

    printf("请输入登录账号:");
    scanf("%s", dlzh);
    printf("请输入登录密码:");
    scanf("%s", dlmm);

    //用登录账号和登录密码跟文件中的进行匹配,如果匹配成功,则登录成功,否则登录失败
    char userName[20];
    char pwd[20];

    //打开文件
    FILE *fp;
    if((fp=fopen("./password.txt", "r")) == NULL)
    {
        perror("fopen error");
        return;
    }

    while(1)
    {
        //从文件中读取一行数据
        int ret = fscanf(fp, "%s %s", userName, pwd);
        //判断
        if(ret < 0)
        {
            printf("登录失败\n");
            return;
        }

        if(strcmp(userName,dlzh)==0 && strcmp(pwd, dlmm)==0)
        {
            printf("登录成功\n");
            return;
        }
    }
}


int main(int argc, const char *argv[])
{
    int menu;      //菜单选项



    for(;;)
    {
        printf("\t\t======1、注册=====\n");
        printf("\t\t======2、登录=====\n");
        printf("\t\t======0、退出=====\n");

        printf("请输入功能:");
        scanf("%d", &menu);

        //对选项多分支选择
        switch(menu)
        {
        case 1:
            {
                //完成注册功能
                registe();
            }
            break;

        case 2:
            {
                //完成登录
                login();
            }
            break;
        case 0:exit(0);     //结束进程
        default:printf("您输入的功能有误,请重新输入!!!\n");
        }
    }

    return 0;
}

2.14 模块读写(fread、fwrite)

       #include 

       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能: 从stream指向的文件中读取nmemb项数据,每一项的大小为size,将结果放入ptr指针容器中
参数1:存储容器
参数2:每一项数据的大小
参数3:项数
参数4:文件指针
返回值:成功返回读取的项数,失败返回一个小于项数的值或者为0
注意:fread并不能区分是文件结束还是读取失败,可以使用feof()、ferror()来判断
      

       size_t fwrite(const void *ptr, size_t size, size_t nmemb,
 FILE *stream);
功能:将ptr指向的数据,每项数据大小为size,一共nmemb项,写入到stream指向的文件中
参数1:存储容器
参数2:每一项数据的大小
参数3:项数
参数4:文件指针
返回值:成功返回读取的项数,失败返回一个小于项数的值或者为0           
1> 对整形数据的读写
#include

int main(int argc, const char *argv[])
{
    FILE *fp;
    //以只写的形式打开文件
    if((fp=fopen("./08test.txt", "w")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    int num = 520;

    fwrite(&num, sizeof(num), 1, fp);        //调用写函数
    //关闭文件
    fclose(fp);


    //重新以只读的形式打开文件
    if((fp = fopen("./08test.txt", "r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //从文件中读取一个数据
    int key = 0;
    fread(&key, sizeof(key), 1, fp);
    //关闭文件
    fclose(fp);

    printf("key = %d\n", key);

    return 0;
}
2> 对结构体数据的读写
#include

struct Stu
{
    char name[20];           //姓名
    int age;                  //年龄
    double score;           //成绩
};




int main(int argc, const char *argv[])
{
    //定义两个学生
    struct Stu s[2] = {{"zhangsan", 20, 80},\
                        {"lisi", 25, 95}};

    //将这两个学生信息全部都存储到文件中
    FILE *fp;
    if((fp = fopen("./09test.txt", "w")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //将数据写入
    fwrite(s, sizeof(struct Stu), 2, fp);

    //关闭文件
    fclose(fp);

    //以只读的形式打开文件
    if((fp=fopen("./09test.txt", "r")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //读取数据
    struct Stu t;
    //fread(&t, sizeof(struct Stu), 1, fp);
    fread(&t, sizeof(struct Stu), 1, fp);
    //关闭文件
    fclose(fp);

    printf("%s\t%d\t%.2lf\n", t.name, t.age, t.score);
    
    return 0;
}

2.15 feof、ferror

       #include 



       int feof(FILE *stream);
 功能:判断文件是否已经到末尾
 参数:文件指针
 返回值:如果到末尾了返回真,否则返回假
              

       int ferror(FILE *stream);
功能:判断文件访问是否出错
参数:文件指针
返回值:如果出错,返回真,否则返回假       

2.16 关于光标的函数(fseek、ftell、rewind)

       #include 

       int fseek(FILE *stream, long offset, int whence);
功能:偏移光标位置
参数1:文件指针
参数2:偏移量:可正、可负、可0
参数3:偏移起始位置
       SEEK_SET:起始位置在文件开头位置
       SEEK_CUR:起始位置为当前位置
       SEEK_END:起始位置在文件结尾
       例如:fseek(fp, 0, SEEK_END);     --->将光标定位在结尾
            fseek(fp, -10, SEEK_END);     --->将光标定位在距离结尾10个字节处
            fseek(fp, 0, SEEK_SET);     --->将光标定位在开头
            fseek(fp, 10, SEEK_SET);     --->将光标定位在开头后的10个字节
            fseek(fp, -10, SEEK_CUR);     --->将光标定位在当前位置前10字节
            fseek(fp, 10, SEEK_CUR);     --->将光标定位在当前位置后10字节
 返回值:成功返回0,失败返回-1并置位错误码
                                                                           

       long ftell(FILE *stream);
功能:返回文件当前的光标位置
参数:文件指针
返回值:光标的偏移量
    例如:
        fseek(fp, 0, SEEK_END);
        ftell(fp);                    ----->    求出文件大小
       

       void rewind(FILE *stream);
功能:将光标定位在开头
参数:文件指针
返回值:无
等价于:fseek(fp, 0, SEEK_SET);       

使用标准IO读写图像内容

#include

int main(int argc, const char *argv[])
{
    //定义文件指针,打开文件
    FILE *fp;
    if((fp=fopen("./kongkong.bmp", "r+")) == NULL)
    {
        perror("fopen error");
        return -1;
    }

    //将指针偏移2个字节
    fseek(fp, 2, SEEK_SET);

    //定义变量接收大小
    unsigned int pixsize ;
    fread(&pixsize, sizeof(pixsize), 1, fp);

    printf("pixsize = %u\n", pixsize);

    //将数据进行更改
    unsigned char color[3] = {255,255,255};    //红色

    //偏移光标到图像位置
    fseek(fp, 54, SEEK_SET);

    //遍历图像
    for(int i=0; i<440; i++)            //外行
    {
        for(int j=0; j<1080; j++)          //内列
        {
            fwrite(color, sizeof(color), 1, fp);
        }
    }
    

    //关闭文件
    fclose(fp);

    return 0;
}

你可能感兴趣的:(算法,数据结构,服务器,linux,c语言)