Linux——标准IO

文件的基础

  • 概念:一组相关数据的有序集合

  • 文件的类型:
    常规文件-r
    目录文件-d
    字符设备文件-c:键盘
    块设备文件-b:U盘 磁盘
    管道文件-p
    套接字文件-s
    符号链接文件-I:快捷方式

标准I/O 流

  • file
    标准IO用一个结构体类型来保存打开的文件的相关信息
    标准的IO操作都是围绕file来进行的

  • 流(stream)
    file有被称为流(stream)
    文本流/二进制流
    在这里插入图片描述

文本流/二进制流

  • window :
    二进制流:换行符 ‘/n’
    文本流:换行符:‘/r’ ‘/n’

  • linux:
    换行符:‘/n’

流的缓冲的类型

  • 全缓冲:缓冲区写满再将数据写入磁盘
  • 行缓冲:当行结束时,将数据写入磁盘
  • 无缓冲:直接读写磁盘

  • 标准的输入流
  • 标准的输出流
  • 标准的错误流

文件的打开和关闭

  • 打开:占用资源

  • 关闭:释放资源

  • 打开函数:FILE *fopen (const char *path, const char *mode);

    • Path:普通文件当前路径不需要加目录,其他要使用完整的路径
    • Mode:
      在这里插入图片描述
    • 返回值:出现错误返回NULL,使用必须判断是否为空

文件的关闭

函数:int fclose(FILE *stream)

  • fclose()调用成功返回0,失败返回EOF(-1),并设置errno
  • fclose()函数的入参stream必须保证为非空,否则出现断错误。

打开关闭练习

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

int main() {
  FILE *fp;
  int ret;
  fp = fopen("test.txt", "r");
  if (fp = NULL) {
    perror("fopen");
    printf("fopen:%s\n", strerror(errno));
  } else {
    printf("Open file success\n");
  }
  ret = fclose(fp);
  if (ret == 0) {
    printf("file close sucess\n");
  } else {
    perror("fclose");
    printf("fclose:%s\n", strerror(errno));
  }
  return 0;
}

字符的输入

读单个字符

  • int fgetc(FILE *stream);
  • int getc(FILE *stream); //宏
  • int getchar(void);

成功时返回读取的字符;若到文件末尾或出错时返回EOF(-1),
getchar()等同于fgetc(stdin)
getc和fgetc区别是一个是宏一个是函数

读取整个行

  • char *gets(char *s); 读取标准输入到缓冲区s
  • char *fgets(char *s, int size, FILE *stream);
    成功时返回s,到文件末尾或出错时返回NULL
    遇到’\n’或已输入size-1个字符时返回,总是包含’\0’

字符的输出

写单个字符

  • int fputc(int c, FILE *stream);
  • int putc(int c, FILE *stream);
  • int putchar(int c);
    成功时返回写入的字符;出错时返回EOF
    putchar©等同于fputc(c, stdout)

读取整个行

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

成功时返回非负整数;出错时返回EOF
puts将缓冲区s中的字符串输出到stdout,并追加’\n’
fputs将缓冲区s中的字符串输出到stream,不追加 ‘\n’

二进制读写

文本文件和二进制的区别:
存储的格式不同:文本文件只能存储文本。

二进制读写函数格式:

  • size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
    void *ptr 读取内容放的位置指针
    size_t size 读取的块大小
    size_t n 读取的个数
    FILE *fp 读取的文件指针

  • size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
    void *ptr 写文件的内容的位置指针
    size_t size 写的块大小
    size_t n 写的个数
    FILE *fp 要写的文件指针

流的刷新

int fflush(FILE *fp);

成功时返回0;出错时返回EOF
将流缓冲区中的数据写入实际的文件
Linux下只能刷新输出缓冲区,输入缓冲区丢弃

如果输出到屏幕使用fflush(stdout)

流的定位:

long ftell(FILE *stream);
long fseek(FILE *stream, long offset, int whence);
void rewind(FILE *stream);
fseek 参数whence参数:SEEK_SET/SEEK_CUR/SEEK_END
SEEK_SET 从距文件开头 offset 位移量为新的读写位置
SEEK_CUR:以目前的读写位置往后增加 offset 个位移量
SEEK_END:将读写位置指向文件尾后再增加 offset 个位移量
offset参数:偏移量,可正可负
注意事项:
1.文件的打开使用a模式 fseek无效
2.rewind(fp) 相当于 fseek(fp,0,SEEK_SET);
3.这三个函数只适用2G以下的文件

格式化输出(重要)

int fprintf(FILE *stream, const char *fmt, …);
int sprintf(char *s, const char *fmt, …);

成功时返回输出的字符个数;出错时返回EOF

格式化输入

int fscanf(FILE *stream, const char *format, …);
int sscanf(const char *str, const char *format, …);

文件IO的API

文件描述符概念:
英文:缩写fd(file descriptor)
是0-1023的数字,表示文件。
0, 1, 2 的含义 标准输入,标准输出,错误

  • 文件IO 打开 open
    int open(const char *pathname, int flags); 不创建文件
    int open(const char *pathname, int flags, mode_t mode); 创建文件,不能创建设备文件
    成功时返回文件描述符;出错时返回EOF

文件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_CREAT | O_APPEND, 0664
a+ —— O_RDWR | O_CREAT | O_APPEND, 0664

  • umask概念:
    umask 用来设定文件或目录的初始权限
  • 文件的关闭
    int close(int fd)
    关闭后文件描述符不能代表文件

对目录的操作

打开目录

#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd); 使用文件描述符,要配合open函数使用
DIR是用来描述一个打开的目录文件的结构体类型
成功时返回目录流指针;出错时返回NULL

读取目录

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

struct dirent是用来描述目录流中一个目录项的结构体类型
包含成员char d_name[256] 参考帮助文档
成功时返回目录流dirp中下一个目录项;
出错或到末尾时时返回NULL

关闭目录

closedir函数用来关闭一个目录文件:
#include <dirent.h>
int closedir(DIR *dirp);

成功时返回0;出错时返回EOF

修改文件权限

chmod/fchmod函数用来修改文件的访问权限:
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);

成功时返回0;出错时返回EOF

获取文件属性

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

成功时返回0;出错时返回EOF
如果path是符号链接stat获取的是目标文件的属性;而lstat获取的是链接文件的属性

练习:使用文件IO实现“每隔1秒向文件1.txt写入当前系统时间,行号递增”

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

int main() {
  int fd;
  int ret;
  time_t ctime;
  struct tm *ctimestr;
  int linecount = 0;
  char rbuf[32];
  char wbuf[32];

  fd = open("1.txt", O_RDWR | O_CREAT | O_APPEND, 0666);
  if (fd < 0) {
    perror("open");
    return 0;
  }

  while (1) {
    memset(rbuf, 0, sizeof(rbuf));
    ret = read(fd, rbuf, sizeof(rbuf)); //写入字符串长度 "\0结束"

    if (ret < 0) {
      perror("write");
      ret = close(fd);
      return 0;
    }
    if (ret == 0) {
      break;
    }
    if (strcmp(rbuf, "\n")) {
      linecount++;
    }
  }

  while (1) {
    ctime = time(NULL);           //获取当前时间
    ctimestr = localtime(&ctime); //转换为结构体格式
    sprintf(wbuf, "%d, %04d-%02d-%02d %02d:%02d:%02d\n", linecount,
            ctimestr->tm_year + 1900, ctimestr->tm_mon + 1, ctimestr->tm_mday,
            ctimestr->tm_hour, ctimestr->tm_min, ctimestr->tm_sec);
    printf("wbuf:%s", wbuf);
    ret = write(fd, wbuf, sizeof(wbuf)); 
    if (ret < 0) {
      perror("write");
      ret = close(fd);
      return 0;
    }
    linecount++;
    sleep(1);
  }

  ret = close(fd);
  if (ret < 0) {
    perror("close");
    return 0;
  }

  return 0;
}

练习:遍历一个文件夹下所有文件,并打印文件权限、大小和日期

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

#define FILENAME "./day5_1"
int main() {
  DIR *dp;
  struct dirent *dt;
  struct stat buf;
  int ret;
  struct tm *t;

  dp = opendir(FILENAME);
  if (dp < 0) {
    perror("opendir");
    return 0;
  }

  while ((dt = readdir(dp)) != NULL) {

    if (strcmp(dt->d_name, ".") == 0 || strcmp(dt->d_name, "..") == 0) {
      continue;
    }
    // printf("%s\n", dt->d_name);

    char name[64] = {0};
    memset(name, 0, sizeof(name));
    memcpy(name, FILENAME, sizeof(FILENAME));
    strcat(name, "/");
    strcat(name, dt->d_name);
    // printf("%s\n", name);
    ret = stat(name, &buf);
    if (ret < 0) {
      perror("stat");
      return 0;
    }

    if (S_ISREG(buf.st_mode)) {
      printf("-");
    }
    if (S_ISDIR(buf.st_mode)) {
      printf("d");
    }
    if (S_ISCHR(buf.st_mode)) {
      printf("c");
    }
    if (S_ISBLK(buf.st_mode)) {
      printf("b");
    }
    if (S_ISFIFO(buf.st_mode)) {
      printf("p");
    }
    if (S_ISSOCK(buf.st_mode)) {
      printf("s");
    }

    for (size_t i = 0; i < 8; i++) {
      if (buf.st_mode & (1 << i)) {
        switch (i % 3) {
        case 2:
          printf("r");
          break;
        case 1:
          printf("w");
          break;
        case 0:
          printf("x");
          break;
        }
      } else {
        printf("-");
      }
    }

    printf(" %d", (int)buf.st_size);

    t = localtime(&buf.st_ctime);

    printf(" %d-%d-%d %d:%d:%d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
           t->tm_hour+8, t->tm_min, t->tm_sec);//小时+8北京时间
    printf(" %s\n", dt->d_name);
  }

  closedir(dp);

  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

li星野

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值