文件与IO

1.open函数

可以打开或创建一个文件。

返回值:成功返回新分配的文件描述符,出错返回-1并设置errno

pathname:打开或创建的文件名,是相对路径or绝对路径。

flags:可同时选择多个常数用按位或运算符连接,宏定义都是以O_开头,表示or。

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

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("usage: cmd filename\n");
        return -1;
    }
    int fd = open(argv[1], O_WRONLY | O_CREAT, 0644);
    if (fd < 0) {
        perror("OPEN");
        return -1;
    }
    return 0;
}

2.close函数

关闭一个已打开的文件。

fd:关闭的文件描述符。当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件

由open返回的文件描述符一定是该进程尚未使用的最小描述符。

3.read函数

从打开的设备或文件中读取数据。

count:请求读取的字节数,读上来的数据保存在缓冲区,同时文件的当前读写位置向后移。

注意:这个读写位置和使用C标准I/O库时的读写位置可能不同,这个读写位置记在内核中,而使用C标准I/O库时读写位置是用户空间I/O缓冲区位置。

有些情况,实际读到字节数会小于请求读的字节数count。如:

①读常规文件时,在读到count个字节之前已达到文件末尾

②从终端设备读,通常以行为单位,读到换行符就返回了。

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

int main(int argc, char *argv[]) {
    char buf[20];
    int n = read(STDIN_FILENO, buf, 10);
    if (n < 0) {
        perror("READ STDIN");
        exit(1);
    }
    printf("read %d bytes\n", n);
    for (int i = 0; i < n; i++) {
        printf("%c", buf[i]);
    }
    putchar(10);

    close(n);
    return 0;
}

4.write函数

向打开的设置或文件中写数据

5.阻塞与非阻塞

阻塞:当进程调用一个阻塞的系统函数时,该进程被置于Sleep状态,这时内核调度其他进程运行,直到该进程等待的事件发生了(如:网络上接收到数据包,调用sleep指定的睡眠时间到)才有可能继续运行。

sleep相对是running状态。在linux内核中,处于运行状态的进程分为两种情况:

正在被调度执行:CPU处于该进程的上下文环境中,程序计数器(eip)保存着该进程的指令地址,正在执行该进程的指令,正在读写该进程的地址空间。

就绪状态:该进程不需要等待什么事情发生,随时都可执行,但CPU暂时还在执行另一个进程,所有该进程在一个就绪队列中等待被内核调度。

如果在open一个设置时指定O_NONBLOCK标志,read/write就不会阻塞。 

以read为例,如果设备暂时没有数据可读就返回-1,通知errno为EWOULDBLOCK(或者EAGAIN),表示本该阻塞在这里,事实上并没有阻塞而是直接返回错误,调用者应该试着再读一次,称为轮询

调用者只是查询一下,而不是阻塞在这里死等,这样可以同时监视多个设备。

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

int main(void)  {
    int fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        perror("OPEN /dev/tty");
        exit(1);
    }

    int n;
    char buf[10];
    int cnt=10;
    while (cnt>0) {
        n = read(fd, buf, 10);
        if (~n) {
           printf("read %d bytes\n", n);
           write(STDOUT_FILENO, buf, n);
           break;
        }
        if (errno != EAGAIN) {
            perror("READ /dev/tty");
            exit(1);
        }
        write(STDOUT_FILENO, "try try?\n", 9);
        sleep(1);
        cnt--;
    }

    close(fd);
    return 0;
}

 6.Iseek

每个打开的文件都记录着当前读写位置,打开文件时读写位置是0,表示文件开头,通常读写多少个字节就会将读写位置往后移多少个字节。

除了O_APPEND打开,每次写操作都会在文件末尾追加数据,然后将读写位置移动新的文件末尾。

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

int main(void) {
    int fd;
    if ((fd=open("./test.txt", O_RDONLY)) < 0) {
        perror("OPEN");
        exit(1);
    }
    char c;
    read(fd, &c, 1);
    write(STDOUT_FILENO, &c, 1);
    int pos = lseek(fd, 3, SEEK_CUR);
    read(fd, &c, 1);
    write(STDOUT_FILENO, &c, 1);
    printf("\npos=%d\n", pos);

    close(fd);
    return 0;
}

7.fcntl

用fcntl函数改变一个已打开的文件的属性而不必重新open文件,可以重新设置读、写、追加、非阻塞等标志。

除了F_GETFL,F_SETFL命令之外,fcntl还有哈恩多命令做其他操作,如:设置文件记录锁。

可以通过fcntl设置的都是当前进程如何访问设备或文件的访问控制属性。

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

int main(void) {
    int flags;
    if ((flags = fcntl(STDIN_FILENO, F_GETFL)) < 0) {
        perror("fcntl get flags");
        exit(1);
    }
    flags |= O_NONBLOCK;
    if ((flags = fcntl(STDIN_FILENO, F_SETFL, flags)) < 0) {
        perror("fcntl set flags");
        exit(1);
    }
    char buf[10];
    ssize_t n;
    while (1) {
        n = read(0, buf, 5);
        if (n >= 0) break;
        if (errno != EAGAIN) {
            perror("read");
            exit(1);
        }
        write(1, "try again?\n", 11);
        sleep(1);
    }
    write(1, buf, n);
    return 0;
}

8.ioctl

用于向设备发控制和配置命令

d:某个设备的文件描述符。

request:ioctl命令,可变参数取决于request,通常是一个指向变量或指针体的指针。

若出错返回-1,若成功返回其他值,返回值也是取决于request。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main(void) {
    struct winsize size;
    if (!isatty(1)) {
        printf("1 is not tty\n");
        exit(1);
    }
    if (ioctl(1, TIOCGWINSZ, &size) < 0) {
        perror("ioctl");
        exit(1);
    }
    printf("%d rows, %d columns\n", size.ws_row, size.ws_col);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值