Linux环境编程——标准IO(二)

在这里插入图片描述
在工作中如果存在日志读取一定用标准IO,因为文件IO没法只读一行

ps:读文件用标准IO,读设备用文件IO,因为蓝牙等设置是实时的,不可能等缓冲区满了再输出,而且标准IO对某些设备可能不支持,而文件IO是底层的,更灵活。

以下三个函数可用于一次读一个字符

int getc(FILE * stream);
int fgetc(FILE *stream);
int getchar(void);

  • 返回值:若成功则为一个字符,若已处文件尾端或出错则为EOF
  • 函数getchar()等同于getc(stdin)
  • 注意,不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferror或feof()
  • getc()的实现是一个宏,而fgetc()是一个函数(用宏效率高一点但代码量比较大,函数开销要大写)
  • 返回值为int类型

为什么get系列函数返回一个int而不是char?
因为返回值包括了有效数据和状态类数据,成功时返回有效数据字符char类型够用,但是出错时char不够返回状态类数据。(返回0-255是成功,-1是失败)

缓存文件按字符的读写

在这里插入图片描述

fgetc是从缓存区中获取一个字符,若缓存区里没数据,就会触发系统调用read从驱动中获取一块数据

  • fgetc并没有引起内核驱动的频繁调用,性能瓶颈仅仅在用户空间调用的次数而已
#include <stdio.h>

#define NEW_FILE_NAME "/tmp/temp/tmp_new.txt"

/*
 * fgetc是从缓存区中获取一个字符,若缓存区里没数据,就会触发系统调用read从驱动中获取一块数据
 *
 * fgetc并没有引起内核驱动的频繁调用,性能瓶颈仅仅在用户空间调用的次数而已
 *
 * 思考,为什么返回值是int类型而不是char类型
 * */
int read_char_lesson(const char *filename) {
    FILE *fp;
    int cnt;

    fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("open");
        return -1;
    }

    cnt = fgetc(fp);
    while (cnt != EOF) {
        printf("the cnt is %x\n", cnt);
        getchar();
        cnt = fgetc(fp);
    }

    return 0;
}

/*
 * 案例:实现一个从标准输入获取内容,写到目标文件的程序
 *
 * 作业:用字符IO编写文件拷贝方法
 * */
int write_lesson1(const char *filename) {
    FILE *fp;
    int buf;

    fp = fopen(filename, "w");
    if (fp == NULL) {
        perror("fopen");
        return -1;
    }

    printf("input: ");
    buf = fgetc(stdin);
    while (buf != EOF){
        fputc((unsigned char)buf, fp);
        buf = fgetc(stdin);
    }
    printf("user input exit...!\n");

    fclose(fp);
    return 0;
}

int main() {
	mkdir("/tmp/temp",0777);
    write_lesson1(NEW_FILE_NAME);

    return 0;
}

在上述代码中,值得注意的是,EOF为一个宏定义,实际上是-1
在这里插入图片描述

#define EOF (-1)

表示 End of file

但是返回EOF时有两种情况,第一种是文件成功,但是文件结束了,另外一种情况是文件出错也返回EOF。因此,更安全的方式是使用feof()函数,来判断文件是否结束
在这里插入图片描述

按行进行读写:

在这里插入图片描述
ps:gets是危险函数,不能用

//删除标准输入的回车信号
buf[strlen(buf)-1]=0;
在这里插入图片描述

  • fgets从标准缓存中读取数据,直到读到一个\n符号就会停止,若缓存区没有数据,则触发系统调用read
  • 读取驱动层数据
  • fgets是字符安全函数,而gets是绝对不要使用的函数
  • fgets不仅约定了\n作为结束标志,也约定了最多读取N-1个符号,会在空间的最后一个字符中添加\0标志
#include <stdio.h>

#define NEW_FILE_NAME "/tmp/temp/tmp_new.txt"
/*
 * fgets从标准缓存中读取数据,直到读到一个\n符号就会停止,若缓存区没有数据,则触发系统调用read
 * 读取驱动层数据
 * fgets是字符安全函数,而gets是绝对不要使用的函数
 * fgets不仅约定了\n作为结束标志,也约定了最多读取N-1个符号,会在空间的最后一个字符中添加\0标志
 * */
int read_lesson1(const char *filename) {
    FILE *fp;
    char buf[16];

    fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("open");
        return -1;
    }

    while (fgets(buf, sizeof(buf)/ sizeof(buf[0]), fp) != NULL) {
        printf("%s", buf);
    }

    fclose(fp);
    return 0;
}

/*
 * 思考题: fputs和puts有什么区别?
 * */

int main() {
    read_lesson1(NEW_FILE_NAME);
}


读写块数据(二进制流数据)

在这里插入图片描述
这里的void *ptr 表示没有指定类型,即任意空间
在这里插入图片描述
第一个案例:写入到指定文件中
在这里插入图片描述
也可以写成:

fwrite(a+1,sizeof(a[0]),4,fp);

从指定文件中读取:

int test2(){
	FILE *fp;
	double buf[4];
	int i;
	fp = fopen("/tmp/temp/a.txt","r");
	memset(buf,0,sizeof(buf));
	fread(buf,sizeof(double),4,fp);
	for(i=0; i<4;i++){
		printf("%f\t",buf[i]);
	}
	printf("\n");
	fclose(fp);
}
  • fwrite写入的是文件缓存区,当缓存区达到一定条件时,才会触发系统调用的write写入到驱动
  • 对于文件来说,默认的触发条件就是缓存区满,而标准输出,则是换行符
  • 对于C语言的字符串结束标志\0,可以写入文件,但是它是一个不可见字符
  • fwrite返回值代表成功写入的元素个数,失败返回的是0

注:
Windows默认编码:GBK
Linux默认编码:UTF-8


在这里插入图片描述

标准IO和文件IO对比

  • 缓存IO和非缓存IO

在这里插入图片描述

文件系统编程

在这里插入图片描述

Linux中有两种类型的链接:

硬链接

  • 是利用Linux中为每个文件分配的物理编号——inode建立链接。因此,硬链接不能跨越文件系统。

软链接(符号链接)

  • 是利用文件的路径名建立链接。通常建立软链接使用绝对路径而不是相对路径,以最大限度增加可移植性。

需要注意:
如果是修改硬链接的目标文件名,链接依然有效;如果修改软链接的目标文件名,则链接将断开;
对一个已存在的文件执行移动或删除操作,将导致指向它软链接的断开。硬链接仍然有效。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Asita_c

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

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

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

打赏作者

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

抵扣说明:

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

余额充值