【文件IO】文件IO学习教程三:标准IO函数/目录

一、关于重新定位问题

1、 重新定位文件流指针 -> fseek() -> man 3 fseek

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

参数:

  • stream:文件指针
  • offset:需要偏移的字节数
  • whence:SEEK_SET -> 相对于开头;SEEK_CUR -> 相对于当前位置;SEEK_END -> 相对于文件末尾

返回值:

  • 成功:0
  • 失败:-1

获取文件大小:

int getFileSize(FILE*fp)
{
    //1、先保存当前文件的位置
    int curPos = ftell(fp);
    //2、将文件偏移到末尾
    fseek(fp,0,SEEK_END);
    //3、获取文件大小
    int fileSize = ftell(fp);
    //4、恢复原来的位置
    fseek(fp,curPos,SEEK_SET);
    //5、返回文件的大小
    return fileSize;
}

2、重置文件指针。 -> rewind() -> man 3 rewind
作用:rewind()用来把文件流的读写位置移至文件开头. 参数 stream 为已打开的文件指针. 此函数相当于调用 fseek(stream, 0, SEEK_SET).
头文件:#include <stdio.h>
函数原型:void rewind(FILE *stream);

参数:
stream:文件流指针
返回值:无


二、printf() 和 fprintf() 输出问题。

printf()输出对象默认是标准输出,标准输出是有缓冲区,也就是说这些缓冲区需要特定的条件才会输出数据。
printf()是一个行缓冲区函数,就是遇到’\n’就会将之前的数据全部输出。


三、fscanf函数

函数作用:从指定的文件stream 获取 指定格式的数据

#include <stdio.h>
int fscanf(FILE *stream, const char *format, ...);

从一个文本中 按照 指定的格式 读取 数据

#include<stdio.h>

int main()
{
    char name[256]={0};
    int age;
    char sex[20]={0};
    //1、打开文件
    FILE* fp = fopen("./info.txt","rb+");
    if(fp == NULL)
    {
        printf("fopen info.txt error\n");
        return -1;
    }
    //以指定的格式从文本fp中获取数据,存储到变量对应的内存空间上
    fscanf(fp,"name:%s age:%d sex:%s",name,&age,sex);
    printf("name:%s age:%d sex:%s\n",name,age,sex);
    
    fclose(fp);
    return 0;
}

四、标准IO其他函数

1、sprintf() -> 保存一个字符串,拼接字符串。

#include <stdio.h>
int sprintf(char *str, const char *format, ...);

参数:

  • str:数据缓冲区
  • format:字符串格式

返回值:

  • ·字符串总字符个数。
#include<stdio.h>

int main()
{
    char *name = "何永成";
    int age = 18;
    char *sex = "男";
    char *city = "广东湛江";
    
    char buf[1024]={0};
    //将上面三个数据 拼接在一起,保存到数组中
    sprintf(buf,"我的名字是:%s 来自:%s 今年芳龄:%d 性别:%s",name,city,age,sex);
    
    printf("%s\n",buf);
    
    return 0;
}

2、getchar() -> 从标准输入缓冲区中获取一个字符。 -> man 3 getchar (用于清空stdin缓冲区)

#include <stdio.h>
int getchar(void);

参数:getchar()会返回读取到的字符, 若返回 EOF 则表示有错误发生.
返回值:

  • 成功: 获取到的字符
  • 失败: EOF
#include <stdio.h>
int main(int argc,char *argv[])
{
    int a;
    char b;
    scanf("%d",&a);  -> 65 + 回车  -> 65就会放置到a变量中
    //把缓冲区的数据清空掉。
    //getchar(); //把\n吃掉
    //while(getchar()!='\n');
    
    scanf("%c",&b);  -> 回车就会放置到b变量。
    
    printf("a = %d\n",a);
    printf("a = %c\n",a);
    printf("b = %d\n",b);
    printf("b = %c\n",b);
    
    return 0;
}

3、getc() -> 从文件指针中获取一个字符 -> man 3 getc

#include <stdio.h>
int getc(FILE *stream);

参数:

  • stream:需要获取字符的文件的文件指针。

返回值:

  • 成功:获取到的字符
  • 失败:EOF
int main()
{
    //从键盘上获取一个字符
    int ch = getc(stdin);//等价于 getchar()    
    printf("%c\n",ch);
    
    return 0;
}

getchar与getc的区别:

  • getchar() -> 固定从标准输入中获取。
  • getc() -> 既可以从标准输入中获取,也可以从文件中获取。

4、 fgetc() -> -> 从文件指针中获取一个字符 -> man 3 fgetc

int fgetc(FILE *stream);等价于 getc()

#include<stdio.h>

int main()
{

    FILE *fp = fopen("./info.txt","rb");
    if(fp == NULL)
{
        printf("fopen error\n");
        return -1;
    }
    
    int ch = fgetc(fp);
    printf("%c\n",ch);
    
    
    fclose(fp);
    
    return 0;
}

5、 putchar() -> man 3 putchar -> 将一个字符输出到标准输出设备上(屏幕)

int putchar(int c);

参数:

  • c: 需要输出的字符

返回值:

  • 成功:输出的字符
  • 失败:EOF
#include <stdio.h>
int main(int argc,char *argv[])
{
    char a = 'x';
    int b;
    b = putchar(a);
    printf("b = %d\n",b);
    printf("b = %c\n",b);
    return 0;
}

6、 putc() -> man 3 putc -> 将一个字符输出到一个指定的文件中。putc 等价于 fputc

int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);

参数:

  • c: 需要处理的那个字符
  • stream: 文件指针

返回值:

  • 成功:输出的字符
  • 失败:EOF
#include<stdio.h>

int main()
{
    //输出一个字符到屏幕终端上
    /* putc('a',stdout);
    putc('\n',stdout); */
    fputc('a',stdout);
    fputc('\n',stdout);//如果不加换行符,此时不会输出
    //while(1);
    
    return 0;
}

7、puts() -> 将一个字符串输出到屏幕,自带换行符。 -> puts(s) 等价于 printf(“%s\n”,s);

int puts(const char *s); -> 只能是标准输出

参数:

  • s 需要处理的字符串

返回值:

  • 成功: 非负整数 字符个数+\n
  • 失败: EOF

int main()
{
    //输出一个字符串到屏幕终端上
    puts("hello world");
    

    return 0;
}

8、 fputs() -> 将一个字符串输出到文件。

int fputs(const char *s, FILE *stream);  -> 既可以是标准输出,也可以是一个文件

参数:

  • s: 需要处理的字符串
  • stream:文件指针

返回值:

  • 成功: 非负整数 1
  • 失败: EOF
#include<stdio.h>

int main()
{
    //输出一个字符串到屏幕终端上
    //fputs("hello world",stdout);
     
    
    FILE *fp = fopen("./1.txt","wb");
    if(fp == NULL)
    {
        printf("fopen error\n");
        return -1;
    }
    //输出一个字符串到指定的文件中
    fputs("hello world\n",fp);
    
    fclose(fp);
    
    return 0;
}

9、fgets() -> 从文件指针中获取一个字符串。 -> man 3 fgets

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

参数:

  • s: 数据缓冲区
  • size: 获取的大小
  • stream: 文件指针

返回值:

  • 成功: 返回s的值。
  • 失败: NULL
int main(int argc,char *argv[])
{
    char buf[100] = {0};
    fgets(buf,100,stdin); //此时也会获取换行符\n
    printf("buf:%s",buf);
    return 0;
}

五、获取文件属性stat

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);

上面三个函数的功能完全一样,区别就是 stat函数传递的就是文件名字,fstat函数传递的是文件描述符,而lstat函数则可以获取链接文件本身的属性。

作用:

  • 获取文件的属性

参数:

  • path: 你要获取哪个文件的属性,将该文件的路径名传递进来
  • buf : 存放文件属性的结构体
  • fd : 你要获取哪个文件的属性,将该文件的文件描述符传递进来

返回值:

  • 成功返回 0
  • 失败返回 -1 ,错误被标记
struct stat {
           dev_t     st_dev;     /* ID of device containing file */常规文件的ID
           ino_t     st_ino;     /* inode number */    文件节点数字 i-node
           mode_t    st_mode;    /* protection */    文件的类型和文件的权限
           nlink_t   st_nlink;   /* number of hard links */ 硬链接数
           uid_t     st_uid;     /* user ID of owner */    用户ID
           gid_t     st_gid;     /* group ID of owner */    组ID
           dev_t     st_rdev;    /* device ID (if special file) */特殊设备ID
           off_t     st_size;    /* total size, in bytes */    文件大小,特殊文件判断不了
           blksize_t st_blksize; /* blocksize for file system I/O */文件系统IO缓冲区的大小,通常是1024
           blkcnt_t  st_blocks;  /* number of 512B blocks allocated */有几块数据,文件系统块大小的单位是512字节
           time_t    st_atime;   /* time of last access 访问(读、写、执行)*/        文件最近一次被存取或被执行的时间
           time_t    st_mtime;   /* time of last modification(写) */    文件最后一次被修改的时间
           time_t    st_ctime;   /* time of last status change */    文件属性更改时间
};

如果你想要获取文件类型:把st_mode传给以下函数就能判断文件类型,如果是则返回真,不是返回假
S_ISREG(m)  is it a regular file?    普通文件
S_ISDIR(m)  directory?            目录文件
S_ISCHR(m)  character device?        字符设备驱动文件
S_ISBLK(m)  block device?        块设备驱动文件
S_ISFIFO(m) FIFO (named pipe)?        管道文件
S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)     软链接文件
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)            套接字文件

1、案例1–获取文件大小

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc ,char**argv)
{
    if(argc<2){
        printf("请先传递文件名\n");
        return -1;
    }
    
    struct stat info;
    
    stat(argv[1],&info);
    
    printf("filesize:%ld\n",info.st_size);
    
    return 0;
}

2、判断文件类型
在这里插入图片描述

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc ,char**argv)
{
    if(argc<2){
        printf("请先传递文件名\n");
        return -1;
    }
    
    struct stat info;
    
    stat(argv[1],&info);
    
    if(S_ISREG(info.st_mode)){
        printf("普通文件\n");
    }
    else if(S_ISDIR(info.st_mode)){
        printf("目录文件\n");
    }
    else if(S_ISCHR(info.st_mode)){
        printf("字符设备文件\n");
    }
    
    return 0;
}

六、时间日期函数

1、time

#include <time.h>
time_t time(time_t *tloc);

作用:

  • 取得目前的时间,也就是从公元 1970 年 1 月 1 日的 UTC 时间从 0 时 0 分 0 秒算起到现在所经过的秒数。

参数:

  • tloc : 如果 tloc 并非空指针的话, 此函数也会将返回值存到 t 指针所指的内存.

返回值:

  • 成功则返回秒数
  • 失败则返回((time_t)-1)值, 错误原因存于 errno 中.
#include<stdio.h>
#include <time.h>

int main()
{
    time_t tloc;
    
    time_t ret = time(&tloc);
    
    printf("ret:%ld tloc:%ld\n",ret,tloc);
    //ret:1644845242 tloc:1644845242

    return 0;
}

2、ctime

#include <time.h>
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);

作用:

  • 将时间和日期以字符串格式表示,一般配合time()函数使用

参数:

  • timep:传递time()函数的返回值
  • buf: 将转换后的格式存储到这里

返回值:

  • 返回一字符串表示目前当地的时间日期.
#include<stdio.h>
#include <time.h>

int main()
{
    char timebuf[1024]={0};

    time_t ret = time(NULL);
    //char *curTime = ctime(&ret);
    char *curTime = ctime_r(&ret,timebuf);
    
    printf("curTime:%s \n",curTime);//curTime:Tue May 11 05:34:47 2021
    printf("timebuf:%s \n",timebuf);//timebuf:Tue May 11 05:34:47 2021

    return 0;
}

3、gmtime

struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);

作用:

  • 取得目前的时间和日期,将参数 timep 所指的 time_t 结构中的信息转换成真实世界所使用的时间日期表示方法, 然后将结果由结构 tm 返回.

参数:

  • timep:time()函数的返回值
  • result:存储转换之后的结果

返回值:

  • 返回目前的时间,存储在结构tm中
struct tm
{
    int tm_sec; //代表目前秒数, 正常范围为 0-59, 但允许至 61 秒
    int tm_min; //代表目前分数, 范围 0-59
    int tm_hour; //从午夜算起的时数, 范围为 0-23
    int tm_mday; //目前月份的日数, 范围 01-31
    int tm_mon; //代表目前月份, 从一月算起, 范围从 0-11
    int tm_year; //从 1900 年算起至今的年数
    int tm_wday; //一星期的日数, 从星期一算起, 范围为 0-6
    int tm_yday; //从今年 1 月 1 日算起至今的天数, 范围为 0-365
    int tm_isdst; //日光节约时间的旗标
};

#include<stdio.h>
#include <time.h>

int main()
{
    time_t tloc;
    
    time_t ret = time(&tloc);
    struct tm *curDateTime = gmtime(&ret);

    printf("date:%d:%d:%d\n",(1900+curDateTime->tm_year),
                 (1+curDateTime->tm_mon),
                 curDateTime->tm_mday);
    
    printf("time:%d:%d:%d\n",curDateTime->tm_hour,
                 curDateTime->tm_min,
                 curDateTime->tm_sec);
    
    return 0;
}

4、localtime

struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);

作用:

  • 取得当地目前时间和日期, 此函数返回的时间日期已经转换成当地时区.

参数:

  • timep:time()函数的返回值
  • result:存储转换之后的结果

返回值:

  • 返回目前的时间,存储在结构tm中
#include<stdio.h>
#include <time.h>

int main()
{
    time_t tloc;
    
    time_t ret = time(&tloc);
    struct tm *curDateTime = localtime(&ret);
    
    printf("date:%d:%d:%d\n",(1900+curDateTime->tm_year),
                 (1+curDateTime->tm_mon),
                 curDateTime->tm_mday);
    
    printf("time:%d:%d:%d\n",curDateTime->tm_hour,
                 curDateTime->tm_min,
                 curDateTime->tm_sec);
    
    return 0;
}

5、asctime

char *asctime(const struct tm * timeptr); 

函数作用:

  • 将结构体所指的本地时间 转换成 字符串本地时间

返回值:

  • 返回本地时间
#include <time.h>
#include <stdio.h>

int main()
{
    time_t t = time(NULL);

    //得到的是本地时间
    struct tm* curTime = localtime(&t);

    printf("date %d/%d/%d ",(1900+curTime->tm_year),
                             (1+curTime->tm_mon),
                             curTime->tm_mday);
    printf("time %d:%d:%d\n",curTime->tm_hour,
                             curTime->tm_min,
                             curTime->tm_sec);    
    //将结构体所指的本地时间  转换成  字符串本地时间                    
    char *curTimeStr = asctime(curTime);                         
    
    printf("curTimeStr:%s\n",curTimeStr);

    
    return 0;
}

七、目录检索

访问文件,可以得到文件里面的数据。
访问目录,可以得到目录下的目录项,该目录项包含文件的名字,文件的类型。
在这里插入图片描述
1)如何打开一个目录? -> opendir() -> man 3 opendir

#include <sys/types.h>
#include <dirent.h>   -> 目录IO专属头文件
DIR *opendir(const char *name);

参数:

  • name:目录的路径

返回值:

  • 成功: 目录流指针
  • 失败: NULL,错误被标记

注意:新打开一个目录,默认目录流指针都是指向目录第一个目录项。
问题: 使用opendir打开一个目录,就等价于切换到该目录下吗?

#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc,char*argv[])
{
    system("pwd");
    
    DIR *dirfp = opendir(argv[1]);
    if(dirfp == NULL)
    {
        perror("opendir error");
        return -1;
    }
    
    system("pwd");
    
    return 0;
}

2)如何在程序中切换路径? -> 在程序中切换,而不是在ubuntu下切换 -> chdir() -> man 2 chdir

//切换工作路径
#include <unistd.h>
int chdir(const char *path);

参数:

  • path: 需要切换的路径 (注意:这个地方不是填目录流指针)

返回值:

  • 成功:0
  • 失败:-1
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc,char*argv[])
{
    system("pwd");
    
    chdir("./aa/");//切换工作路径到当前目录下的子目录aa里面
    
system("pwd");
    
    return 0;
}

3)如何读取目录下的内容? -> readdir() -> man 3 readdir

#include <dirent.h>
struct dirent *readdir(DIR *dirp);

参数:

  • dirp: 目录流指针。

返回值:

  • 成功:目录项指针 struct dirent *
  • 失败:NULL -> 读完了目录中的所有项,还继续读,那么就会返回NULL。
struct dirent 
{ 
    ino_t d_ino; // 文件索引号 
    off_t d_off; // 目录项偏移量 
    unsigned short d_reclen; // 该目录项大小 
    unsigned char d_type; // 文件类型 
    char d_name[256]; // 文件名 
}; 

d_type: 在/usr/include/dirent.h 中定义了
DT_BLK  6    This is a block device.   -> 块设备
DT_CHR  2    This is a character device.  -> 字符设备
DT_DIR  4    This is a directory.       -> 目录
DT_FIFO 1    This is a named pipe (FIFO).  -> 管道
DT_LNK  10    This is a symbolic link.    -> 链接
DT_REG  8   This is a regular file.       -> 普通文件
DT_SOCK 12   This is a UNIX domain socket.  -> 套接字文件
DT_UNKNOWN 0 The file type is unknown.   -> 未知类型

4)关闭目录。 -> closedir() -> man 3 closedir

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

参数:

  • dirp: 目录流指针。

返回值:

  • 成功:0
  • 失败:-1

注意:每次调用readdir函数,只能读取一个文件,如果你想要读取某个目录下所有的文件,可以不断循环调用readdir函数

// 案例:打印指定目录下的文件名
#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include<string.h>

int main(int argc,char*argv[])
{    
    //打开目录
    DIR *dirfp = opendir(argv[1]);
    if(dirfp == NULL)
    {
        perror("opendir error");
        return -1;
    }
    while(1)
    {
        //读取目录
        struct dirent *info = readdir(dirfp);
        if(info == NULL)//如果读取完了 退出
            break;
        
        printf("d_ino:%ld d_off:%ld d_reclen:%d d_name:%s d_type:%d\n",info->d_ino,info->d_off,info->d_reclen,info->d_name,info->d_type);
    }
    
    //关闭目录文件
    closedir(dirfp);
    
    return 0;
}
// 将指定目录下的bmp结尾的普通文件路径名(./1.bmp     ./2.bmp     ./3.bmp),存储到数组中

#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include<string.h>

#define BMP_NUMBER    100  //最大只能支持读取100张图片
#define BMPDIR        "./resource"
//效果:从 指定的目录中读取 所有bmp图片的名字,存储到数组中

int main()
{
    char bmpName[BMP_NUMBER][256]={0};//存储图片的名字
    int bmpCount=0; //记录当前加载进来的bmp图片数量
    int i;
    
    //打开目录
    DIR *dirfp = opendir(BMPDIR);
    if(dirfp == NULL)
    {
        perror("opendir error");
        return -1;
    }
    while(1)
    {
        //读取目录
        struct dirent *info = readdir(dirfp);
        if(info == NULL)//如果读取完了 退出
            break;
        
        printf("d_name:%s\n",info->d_name); //info->d_name  ---1.bmp
        
        //去除 . 和 ..     而且 文件 是 普通 文件
        if(info->d_name[0] != '.' && info->d_type == DT_REG)
        {
            //bmpName[0]---> ./reource/1.bmp
            //将图片的路径 和 名字 拼接起来
            char pathName[256]={0};
            sprintf(pathName,"%s/%s",BMPDIR,info->d_name);
            strcpy(bmpName[bmpCount++],pathName); // info->d_name[256]   char d_name[256] = "1.bmp"
        }
        
    }
    //将存储到数组中所有的图片名字都打印出来
    for(i=0; i<bmpCount; i++)
    {
        printf("bmpName[%d]:%s\n",i,bmpName[i]);
    }
    
    //关闭目录文件
    closedir(dirfp);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值