Linux_标准IO

1.标准IO

1.1什么是FILE

在使用fopen打开文件的时候,会返回一个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: 标准出错

1.2fopen的使用

 man 后跟的数字的含义
 	2   系统调用(内核提供的函数)
   3   库调用(程序库中的函数)
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
功能:使用标准IO打开文件
参数:
   @pathname: 路径/文件名 "./hello.txt"
   @mode:打开文件的方式 "r" "r+"
    r:以只读的方式打开文件,将文件中的光标定位在文件的开头
    r+:以读写的方式打开文件,将文件中的光标定位在文件的开头
    w:以只写的方式打开文件,如果文件不存在就创建文件,如果文件存在就清空,将光标定位在开头 
    w+:以读写的方式打开文件,如果文件不存在就创建文件,如果文件存在就清空,将光标定位在开头  
    a:以追加(结尾写)的方式打开文件,如果文件不存在就创建文件,将光标定位在文件的结尾
    a+:以读和追加(结尾写)的方式打开文件,如果文件不存在就创建文件,如果读从开头读,写在文件的结尾写
返回值:成功返回文件指针,失败返回NULL,置位错误码

fopen的实例:

#include <stdio.h>

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

    //以只写的方式打开文件
    // fp = fopen("./hello.txt","w");
    // if(fp == NULL){
    //     printf("create file error\n");
    //     return -1;
    // }

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

    //以追加的方式打开文件,如果文件存在,不会清空(追加)
    fp = fopen("./hello.txt","a");
    if(fp == NULL){
        printf("create file error\n");
        return -1;
    }

    return 0;
}

1.3fclose的使用

int fclose(FILE *stream);
功能:关闭文件
参数:
   @stream:文件指针
返回值:成功返回0,失败返回EOF(end of file),并置位错误码
		#define EOF (-1)

fclose的使用:

#include <stdio.h>

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

    //关闭文件
    if(fclose(fp)<0){
        printf("close file error\n");
        return -1;
    }
    if(fclose(stdin)<0){
        printf("close file error\n");
        return -1;
    }
    if(fclose(stdout)<0){
        printf("close file error\n");
        return -1;
    }
    if(fclose(stderr)<0){
        printf("close file error\n");
        return -1;
    }
    return 0;
}

1.4关于错误码的问题

在文件IO或标准IO相关接口被调用的时候,如果出错了,操作系统会给应用程序返回错误码。过程如下:
在这里插入图片描述

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

1.4.1strerror函数的使用

#include <stdio.h>
#include <errno.h>
#include <string.h>
//extern int errno;

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

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

    fclose(fp);
    return 0;
}

1.4.2perror函数的使用

#include <stdio.h>

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;
}

1.5fgetc/fputc函数使用

int fgetc(FILE *stream);
功能:从文件中读取一个字符
参数:
   @stream:文件指针
返回值:成功返回字符的ascii,读取文件的结尾EOF,失败返回error
    
int fputc(int c, FILE *stream);
功能:向文件中写一个字符
参数:
   @c:被写字符的ascii
  	@stream:文件指针
返回值:成功返回ascii,失败返回EOF  

1.5.1fputc函数的使用

#include <stdio.h>

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;
}

1.5.2fgetc函数的使用

#include <stdio.h>

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;
}

1.5.3请使用fgetc统计文件的行数

#include <stdio.h>

int main(int argc,const char * argv[])
{
    FILE * fp;
    char ch;
    int count=0;
    //1.通过命令行输入可执行程序和文件名,否则就出错
    if(argc != 2){
        printf("input error,try agian\n");
        printf("usage:./a.out filename\n");
        return -1;
    }
	//2.以只读的方式打开文件
    if((fp = fopen(argv[1],"r"))==NULL){
        perror("fopen error");
        return -1;
    }
    //3.只要没有到文件结尾,循环就一直执行(EOF)
    while((ch = fgetc(fp)) != EOF){
        if(ch == '\n'){   //如果文件中有'\n'就让行号+1
            count++;
        }
    }

    printf("file line number = %d\n",count+1);
		
    //关闭文件
    fclose(fp);

    return 0;
}

1.5.4请使用fgets/fputc拷贝一个文件

#include <stdio.h>

int main(int argc, const char *argv[])
{
    FILE *sfp, *dfp;
    char ch;

    if (argc != 3)
    {
        printf("input error,try agian\n");
        printf("usage:./a.out srcfile destfile\n");
        return -1;
    }

    if ((sfp = fopen(argv[1], "r")) == NULL)
    {
        perror("fopen src file error");
        return -1;
    }
    if ((dfp = fopen(argv[2], "w")) == NULL)
    {
        perror("fopen dest file error");
        return -1;
    }
    while ((ch = fgetc(sfp)) != EOF)
    {
       fputc(ch,dfp);
    }

    fclose(sfp);
    fclose(dfp);

    return 0;
}

1.6fgets/fputs函数使用

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

在这里插入图片描述

int fputs(const char *s, FILE *stream);
功能:将s字符串中的内容写入到文件中
参数:
   @s:首地址
   @stream:文件指针
返回值:成功返回写入的字符的个数,失败返回EOF

1.6.1使用fgets从stdin中读取字符串

#include <stdio.h>
#include <string.h>

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

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


    printf("%s\n",buffer);

    return 0;
}

1.6.2fputs函数的使用

#include <stdio.h>

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;
}

1.6.3使用fgets统计文件的行号

在这里插入图片描述

#include <stdio.h>
#include <string.h>

int main(int argc,const char * argv[])
{
    FILE *fp;
    char s[10];
    int line=0;
    if(argc != 2){
        fputs("input error,try again\n",stderr);
        fputs("usage:./a.out file\n",stderr);
    }

    if((fp = fopen(argv[1],"r"))== NULL){
        perror("fopen error");
        return -1;
    }

    while(fgets(s,sizeof(s),fp)!=NULL){
        if(strlen(s)==sizeof(s)-1){
            if(s[sizeof(s)-2]!='\n'){
                continue;
            }
        }
         line++;
    }

    printf("line = %d\n",line);
   
    fclose(fp);

    return 0;
}

1.6.4使用fgets和fputs实现文件的拷贝

#include <stdio.h>

int main(int argc, const char *argv[])
{
    FILE *sfp, *dfp;
    char s[40];
    if (argc != 3)
    {
        printf("input error,try agian\n");
        printf("usage:./a.out srcfile destfile\n");
        return -1;
    }

    if ((sfp = fopen(argv[1], "r")) == NULL)
    {
        perror("fopen src file error");
        return -1;
    }
    if ((dfp = fopen(argv[2], "w")) == NULL)
    {
        perror("fopen dest file error");
        return -1;
    }

    while(fgets(s,sizeof(s),sfp)!=NULL){
        fputs(s,dfp);
    }

    fclose(sfp);
    fclose(dfp);

    return 0;
}

2.格式化控制相关的函数

2.1sprintf函数使用(将字符串格式化到数组中)

int sprintf(char *str, const char *format, ...);
功能:向str中进行字符串的格式化
参数:
    @str:首地址
    @format:控制格式
返回值:成功格式化字符的个数,失败返回负数
 
char s[50];
sprintf(s,"%4d-%02d-%02d %02d:%02d:%02d\n",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往数组中写入字符的时候,如果出现越界,虽然编译的时候会提示警告,但是在程序运行的时候有多少字符就格式化多少字符,这个内存越界的错误

2.2snprintf函数使用(将字符串格式化到数组中)

int snprintf(char *str, size_t size, const char *format, ...);
功能:将字符串格式化到str的数组中
参数:
   @str:存放格式化后的字符串的内存首地址
   @size:大小(字符size-1)
   @format:格式化的控制格式
返回值:成功返回字符的个数,失败返回负数
#include <stdio.h>

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

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

2.3fprintf的使用(将格式化后的字符串向对应的文件指针中输出)

int fprintf(FILE *stream, const char *format, ...);
功能:将格式化后的字符串向对应的文件指针中输出
参数:
   @stream:文件指针
   @format:控制格式
返回值:成功返回>0,失败返回<0   
#include <stdio.h>
#include <time.h>
#include <string.h>
int getLineNum(FILE*fp)
{
    char s[10];
    int line=0;
    while (fgets(s, sizeof(s), fp) != NULL)
    {
        if (strlen(s) == sizeof(s) - 1)
        {
            if (s[sizeof(s) - 2] != '\n')
            {
                continue;
            }
        }
        line++;
    }
    return line;
}
int main(int argc, const char *argv[])
{
    FILE *fp;
    time_t time_new, time_old;
    struct tm *tm;
    char s[50];
    int line = 0;

    if ((fp = fopen("tim.txt", "a+")) == NULL)
    {
        perror("fopen src file error");
        return -1;
    }

    line=getLineNum(fp);
    printf("line = %d\n",line);
    while (1)
    {
        time(&time_new);

        tm = localtime(&time_new);
        if (tm == NULL)
        {
            perror("change time error");
            return -1;
        }

        if (time_new != time_old)
        {
            time_old = time_new;
            fprintf(fp,"%3d.%4d-%02d-%02d %02d:%02d:%02d\n", 
            ++line, tm->tm_year + 1900,tm->tm_mon + 1, 
            tm->tm_mday, tm->tm_hour, tm->tm_min, 
            tm->tm_sec);
       
            fflush(fp);
        }
    }

    fclose(fp);
    return 0;
}

3.fread/fwrite函数的使用

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件中读取数据到ptr中
参数:
   @ptr:保存读取到数据的首地址
   @size:每一项的大小
   @nmemb:项的个数
  	@stream:文件指针
返回值:成功返回读取到的项目的个数,
     如果是失败或者读取到的文件的结尾返回值是要小于nnemb或者0
     错误还是读取到文件的结尾需要通过feof(fp)或者ferror(fp)来判断
        
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:将ptr中的数据写入到文件中
参数:
   @ptr:数据的首地址
   @size:每一项的大小
   @nmemb:项的个数
  	@stream:文件指针
返回值:成功返回写的项目的个数,
     如果是失败返回值是要小于nnemb或者0

3.1fwrite/fread函数的使用

3.1.1fwrite/fread整数读写

#include <stdio.h>

#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)
int main(int argc,const char * argv[])
{
    FILE *fp;
    int num=1234;
  
    if((fp = fopen("test.txt","w"))==NULL)
        PRINT_ERR("fopen error");

    fwrite(&num,4,1,fp);
	  //写入的整数,虽然在文本编辑器中看到的是乱码,但是可以通过fread正确读取到
    fclose(fp);
    return 0;
}
#include <stdio.h>

#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 = %d\n",num);
    fclose(fp);
    return 0;
}

3.1.2fwrite/fread字符串读写

#include <stdio.h>
#include <string.h>
#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)
int main(int argc,const char * argv[])
{
    FILE *fp;
    char str[] = "this is test for fwrite string";
  
    if((fp = fopen("test.txt","w"))==NULL)
        PRINT_ERR("fopen error");

    fwrite(str,1,strlen(str),fp);

    fclose(fp);
    return 0;
}
#include <stdio.h>

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

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

    fread(str,1,sizeof(str),fp);

    printf("read str = %s\n",str);
    fclose(fp);
    return 0;
}

3.1.3fwrite/fread结构体读写

typedef struct{
    char name[20];
    char sex;
    int score;
}stu_t;
#include <stdio.h>
#include <string.h>
#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)

typedef struct{
    char name[20];
    char sex;
    int score;
}stu_t;

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

    stu_t stu = {
        "zhangsan",
        'm',
        99,
    };
  
    if((fp = fopen("test.txt","w"))==NULL)
        PRINT_ERR("fopen error");

    fwrite(&stu,sizeof(stu),1,fp);

    fclose(fp);
    return 0;
}
#include <stdio.h>

#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)
typedef struct{
    char name[20];
    char sex;
    int score;
}stu_t;
int main(int argc,const char * argv[])
{
    FILE *fp;
    stu_t stu;

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

    fread(&stu,sizeof(stu),1,fp);

    printf("name = %s,sex = %c,score = %d\n",
    stu.name,stu.sex,stu.score);
    fclose(fp);
    return 0;
}

3.1.4feof/ferror函数的使用

#include <stdio.h>
#include <string.h>
#define PRINT_ERR(msg) do{perror(msg);return -1;}while(0)

int main(int argc,const char * argv[])
{
    FILE *fp;
    char buf[10] = {0};

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

    while(1){
        //memset将buf中的内容全部写为0,大小是是sizeof(buf)
        memset(buf,0,sizeof(buf));
        fread(buf,1,sizeof(buf),fp);
        printf("%s",buf);

        if(feof(fp)){
            fprintf(stderr,"读取到文件的结尾了\n");
            break;
        }else if(ferror(fp)){
            fprintf(stderr,"读取到文件出错了\n");
            break;
        }
        
    }
    
    fclose(fp);
    return 0;
}

3.1.5使用fread/fwrite实现拷贝文件的功能

#include <stdio.h>
#include <string.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc, const char *argv[])
{
    FILE *sfp, *dfp;
    char buf[10];
    int ret;
    if(argc != 3){
        fprintf(stderr,"input error, tryagain\n");
        fprintf(stderr,"usage:./a.out srcfile destfile");
        return -1;
    }

    if ((sfp = fopen(argv[1], "r")) == NULL)
        PRINT_ERR("fopen error");

    if ((dfp = fopen(argv[2], "w")) == NULL)
        PRINT_ERR("fopen error");
	 
    //如果没有到文件的结尾并且没有出错,就执行循环
    //如果读取到结尾或者出错,就退出循环
    while (!(feof(sfp) || ferror(sfp)))
    {
        // memset将buf中的内容全部写为0,大小是是sizeof(buf)
        //memset(buf, 0, sizeof(buf));
        //上述的memset可以不写,原因是通过ret来决定写入字符的个数
        //即使buf中没有'\0'的结束符,也是可以正常执行的
        ret = fread(buf, 1, sizeof(buf), sfp);
        fwrite(buf,1,ret,dfp);

    }

    fclose(sfp);
    fclose(dfp);
    return 0;
}

4.关于光标位置的相关函数(fseek/ftell/rewind)

int fseek(FILE *stream, long offset, int whence);
功能:修改光标的位置
参数:
   @stream:文件指针
   @offset:偏移
       	>0 向后偏移
       =0  不偏移
       <0  向前偏移
   @whence:
			SEEK_SET,开头
			SEEK_CUR,当前位置
			SEEK_END,结尾
返回值:成功返回0,失败返回-1置位错误码
eg:
	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);将光标定位在文件结尾          
                
long ftell(FILE *stream)
功能:获取光标当前的位置
参数:
   @stream:文件指针
返回值:成功返回光标的位置,失败返回-1,置位错误码
eg:
fseek(fp,0,SEEK_END);	
ftell(fp);   ===>功能统计文件所占用的字符的个数(大小)

void rewind(FILE *stream);
功能:恢复光标的位置到文件的开头
参数:
   @stream:文件指针   
返回值:无
eg:
 rewind(fp) == fseek(fp,0,SEEK_SET)  等价
#include <stdio.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    FILE * fp;
    char s[50];
    if ((fp = fopen("./test.txt", "r")) == NULL)
        PRINT_ERR("fopen error");

    fseek(fp,6,SEEK_SET);
    fgets(s,sizeof(s),fp);
    printf("s = %s\n",s);

    fclose(fp);

    return 0;
}

思考:如果通过追加的方式打开文件,修改光标的位置是否能影响读写?

答:如果是以"a"打开文件,修改不了光标的位置,在想文件中写数据的时候总是在结尾写

如果是以"a+"打开文件,修改光标影响不了写的光标的位置,但是可以影响读的光标的位置

#include <stdio.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    FILE * fp;
    char s[50];
    if ((fp = fopen("./test.txt", "a")) == NULL)
        PRINT_ERR("fopen error");

    fseek(fp,0,SEEK_SET);  //将追加是结尾的光标修改到文件的开头,在向文件中写
                     //数据的时候依然是在结尾写,影响不了写的光标的位置
    fprintf(fp,"i am test fseek func append");

    fclose(fp);

    return 0;
}
#include <stdio.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    FILE * fp;
    char s[50];
    if ((fp = fopen("./test.txt", "a+")) == NULL)
        PRINT_ERR("fopen error");

    fseek(fp,6,SEEK_SET);   //可以影响读的光标的位置
    fgets(s,sizeof(s),fp);
    printf("s = %s\n",s);

    fclose(fp);

    return 0;
}

作业1

将当前的时间写入到tim.txt的文件中,如果ctrl+c退出之后,在再次执行支持断点续写

1.2022-04-26 19:10:20

2.2022-04-26 19:10:21

3.2022-04-26 19:10:22

//按下ctrl+c停止,再次执行程序

4.2022-04-26 20:00:00

5.2022-04-26 20:00:01

获取系统时间的函数

#include <time.h>
time_t time(time_t *tloc);
功能:获取系统当前时间的秒钟数
参数:
    @tloc:如果是NULL,通过返回值返回秒钟数
         如果不是NULL,通过参数得到秒钟数
返回值:成功返回time_t的地址,失败返回(time_t*-1,并置位错误码
struct tm *localtime(const time_t *timep);
功能:将秒钟转化为年月日时分秒的格式
参数:
   @timep:秒钟数
返回值:成功返回tm的结构体指针,失败返回NULL,置位错误码
   struct tm {
       int tm_sec;   //秒钟
       int tm_min;   //分钟
       int tm_hour;  //小时
       int tm_mday;  //天
       int tm_mon;   //月+1
       int tm_year;  //年+1900
       int tm_wday;   /* 周几 (0-6, Sunday = 0) */
       int tm_yday;   //一年内的第几天
       int tm_isdst;  //夏令时,已经被废弃了
   };
#include <stdio.h>
#include <time.h>
int main(int argc,const char * argv[])
{
    time_t time_v;
    struct tm *tm;
    time(&time_v);

    tm = localtime(&time_v);
    if(tm == NULL){
        perror("change time error");
        return -1;
    }

    printf("%4d-%02d-%02d %02d:%02d:%02d\n",tm->tm_year+1900,
    tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);

    return 0;
}

sprintf函数的使用

int sprintf(char *str, const char *format, ...);
功能:向str中进行字符串的格式化
参数:
    @str:首地址
    @format:控制格式
返回值:成功格式化字符的个数,失败返回负数
 
char s[50];
sprintf(s,"%4d-%02d-%02d %02d:%02d:%02d\n",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中的字符串写入到文件中
#include <stdio.h>
#include <time.h>
int main(int argc,const char * argv[])
{
    FILE *fp;
    time_t time_v;
    struct tm *tm;
    char s[50];
    if ((fp = fopen("hello.txt", "a")) == NULL)
    {
        perror("fopen src file error");
        return -1;
    }
    time(&time_v);

    tm = localtime(&time_v);
    if(tm == NULL){
        perror("change time error");
        return -1;
    }

    sprintf(s,"%4d-%02d-%02d %02d:%02d:%02d\n",tm->tm_year+1900,
    tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);

    fputs(s,fp);
    fclose(fp);
    return 0;
}
#include <stdio.h>
#include <time.h>
int main(int argc,const char * argv[])
{
    FILE *fp;
    time_t time_v;
    struct tm *tm;
    char s[50];
    if ((fp = fopen("hello.txt", "a")) == NULL)
    {
        perror("fopen src file error");
        return -1;
    }
    time(&time_v);

    tm = localtime(&time_v);
    if(tm == NULL){
        perror("change time error");
        return -1;
    }

    sprintf(s,"%4d-%02d-%02d %02d:%02d:%02d\n",tm->tm_year+1900,
    tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);

    fputs(s,fp);
    fclose(fp);
    return 0;
}

作业:向文件中打印系统时间

#include <stdio.h>
#include <time.h>
#include <string.h>
int getLineNum(FILE*fp)
{
    char s[10];
    int line=0;
    while (fgets(s, sizeof(s), fp) != NULL)
    {
        if (strlen(s) == sizeof(s) - 1)
        {
            if (s[sizeof(s) - 2] != '\n')
            {
                continue;
            }
        }
        line++;
    }
    return line;
}
int main(int argc, const char *argv[])
{
    FILE *fp;
    time_t time_new, time_old;
    struct tm *tm;
    char s[50];
    int line = 0;

    if ((fp = fopen("tim.txt", "a+")) == NULL)
    {
        perror("fopen src file error");
        return -1;
    }

    line=getLineNum(fp);
    printf("line = %d\n",line);
    while (1)
    {
        time(&time_new);

        tm = localtime(&time_new);
        if (tm == NULL)
        {
            perror("change time error");
            return -1;
        }

        if (time_new != time_old)
        {
            time_old = time_new;
            
            sprintf(s, "%3d.%4d-%02d-%02d %02d:%02d:%02d\n", 
            ++line, tm->tm_year + 1900,tm->tm_mon + 1, 
            tm->tm_mday, tm->tm_hour, tm->tm_min, 
            tm->tm_sec);
            
            fputs(s, fp);
            fflush(fp);
        }
    }

    fclose(fp);
    return 0;
}

作业2

使用标准IO对文件打马赛克

使用标准IO对图片操作

自己编写一个head.h的头文件,将它放在/usr/include/目录下,以后包含这个头文件,就可以使用打印的宏

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <string.h>

#define PRINT_ERR(msg) do{ \
        perror(msg);\
        return -1;\
    }while(0)

#endif    

bmp的图片格式详解

参看这篇文章:https://www.ivu4e.com/blog/image/2019-09-04/183.html

在ubuntu终端上可以通过eog xxx.bmp打开一张图片

bmp文件操作实例

#include <head.h>

int main(int argc, const char *argv[])
{
    FILE *fp;
    int img_size;
    unsigned char color[3] = {0x0, //蓝
                              0x0,//绿
                              0xff};  //红
    if (argc != 2)
    {
        fprintf(stderr, "input error,try again\n");
        fprintf(stderr, "usage:./a.out picture.bmp\n");
        return -1;
    }
    if ((fp = fopen(argv[1], "r+")) == NULL)
        PRINT_ERR("fopen error");

    fseek(fp, 2, SEEK_SET);
    fread(&img_size, 4, 1, fp);

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

    fseek(fp, 54, SEEK_SET); //跳过图片的头

    for (int j = 0; j < 100; j++) //写多少行
    {
        for (int i = 0; i < 2560; i++) //每一行内的像素点
        {
            fwrite(color, 3, 1, fp); //每一个点占3个字节
        }
    }

    fclose(fp);

    return 0;   
}

给图片打马赛克

#include <head.h>
#include <stdlib.h>

typedef struct{
    unsigned int img_size; //图片的大小
    unsigned int img_width;//图片的宽
    unsigned int img_high; //图片的高
    unsigned short img_bitcount; //一个像素点占用的bit(24bit)
}image_info_t;

typedef struct{
    unsigned char b;
    unsigned char g;
    unsigned char r;
}point_t;

void show_image_info(image_info_t *info)
{

    printf("size = %d,width = %d,high = %d,bitcount = %d\n",
    info->img_size,info->img_width,info->img_high,info->img_bitcount);
}

void get_image_info(FILE*fp,image_info_t *info)
{
    fseek(fp,2,SEEK_SET);
    fread(&info->img_size,1,4,fp); //图片的大小

    fseek(fp,18,SEEK_SET);
    fread(&info->img_width,1,4,fp); //图片的宽

    fread(&info->img_high,1,4,fp); //读取图片的高

    fseek(fp,2,SEEK_CUR);
    fread(&info->img_bitcount,1,2,fp); //像素点占用的bit
}

void copy_image_file(FILE*sfp,FILE*dfp)
{
    int ret;
    char buf[1024] = {0};
    
    while(!(feof(sfp)||ferror(sfp))){
        ret = fread(buf,1,sizeof(buf),sfp);
        fwrite(buf,1,ret,dfp);
    }
    
    return;
}
void set_image_mosaic(FILE *fp,image_info_t *info,int x,int y)
{
    int i,j,k,w;
    point_t color = {0,0,0xff};
    char *buffer = (char *)malloc((info->img_width)*(info->img_high)*3);
    //point_t arr[612][440];
    //1.将图像读取回来
    fseek(fp,54,SEEK_SET);
    fread(buffer,1,(info->img_size-54),fp);
    //2.修改
    //i:整体的高/10
    //j:整体的宽除以10
    //k:块的高
    //w:块的宽
    for(i=0;i<info->img_high/y;i++){
        for(j=0;j<info->img_width/x;j++){
            //读取小方块中最左上角的像素点
            color = *(point_t *)(buffer+(j*3*x)+(i*y*info->img_width*3));
            for(k=0;k<y;k++){
                for(w=0;w<x;w++){
                      *(point_t*)(buffer+w*3+(k*info->img_width*3)+
                      (j*3*x)+(i*y*info->img_width*3)) = color;
                }
            }
        }
    }

    //3.重新将图像写回去
    fseek(fp,54,SEEK_SET);
    fwrite(buffer,1,(info->img_size-54),fp);
}
int main(int argc, char const *argv[])
{
    FILE *sfp,*dfp;
    int size;
    image_info_t info;
    char new_name[20] = {0};

    if(argc != 2){
        fprintf(stderr,"input error,try again\n");
        fprintf(stderr,"usage:./a.out xxxx.bmp\n");
        return -1;
    }
    //1.打开文件并拷贝文件 milaoshu.bmp
    if((sfp = fopen(argv[1],"r"))==NULL)
        PRINT_ERR("open error");
    
    //构造一个新图片的字符串  new_milaoshu.bmp
    snprintf(new_name,sizeof(new_name),"new_%s",argv[1]);

    //打开新图片,如果不存在就创建,如果存在就清空
    if((dfp = fopen(new_name,"w+"))==NULL)
        PRINT_ERR("open error");

    //图片的拷贝,将milaoshu.bmp-->new_milaoshu.bmp    
    copy_image_file(sfp,dfp);

    //2.获取图片前54个字节中有用的信息
    get_image_info(dfp,&info);

    show_image_info(&info);

    //3.尝试打马赛克
    //10,10:代表的是打马赛克每个小方块的大小
    //10*3= 30
    //10  = 10行
    set_image_mosaic(dfp,&info,10,10);

    //4.关闭源文件和目标文件
    fclose(sfp);   
    fclose(dfp); 
    return 0;
}

在这里插入图片描述

作业3:

使用文件IO实现,将当前的时间写入到tim.txt的文件中

2022-04-26 19:10:20

2022-04-26 19:10:21

2022-04-26 19:10:22

使用文件IO写入时间

#include <head.h>
#include <time.h>

int main(int argc, const char *argv[])
{
    int fd;
    time_t time_new, time_old;
    struct tm *tm;
    char s[50] = {0};

    if ((fd = open("tim.txt",O_RDWR|O_APPEND|O_CREAT,0664)) == -1)
        PRINT_ERR("open error");

    while (1)
    {
        time(&time_new);

        tm = localtime(&time_new);
        if (tm == NULL)
        {
            perror("change time error");
            return -1;
        }

        if (time_new != time_old)
        {
            time_old = time_new;
            sprintf(s, "%4d-%02d-%02d %02d:%02d:%02d\n",
            tm->tm_year + 1900,tm->tm_mon + 1, 
            tm->tm_mday, tm->tm_hour, tm->tm_min, 
            tm->tm_sec);
            
            write(fd,s,strlen(s));
        }
    }

    close(fd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值