Linux文件 IO 和标准 IO简介

1 篇文章 0 订阅

        文件 IO 是 Linux 系统提供的接口, 针对文件和磁盘进行操作, 不带缓存机制; 标准 IO 是 C 语言函数库里的标准 I/O 模型, 在 stdio.h 中定义, 通过缓冲区操作文件, 带缓存机制。 Linux 系统中一切皆文件, 包括普通文件, 目录, 设备文件(不包含网络设备) , 管道, fifio 队列, socket 套接字等, 在终端输入“ls -l”可查看文件类型和权限。
标准 IO 和文件 IO 常用 API 如下:

标准 IO文件 IO
打开/创建fopenopen
getc,fgetc,getchar,fgets,gets,
fread
read
putc,fputc,putc,fputs,puts,
fwrite
write
关闭fcloseclose

标准 IO 和文件 IO 的区别如下图所示:

         文件 IO 是直接调用内核提供的系统调用函数, 头文件是 unistd.h, 标准 IO 是间接调用系统调用函数,头文件是 stdio.h, 文件 IO 是依赖于 Linux 操作系统的, 标准 IO 是不依赖操作系统的, 所以在任何的操作系统下, 使用标准 IO, 也就是 C 库函数操作文件的方法都是相同的。
        对于文件 IO 来说, 一切都是围绕文件操作符来进行的。 在 Linux 系统中, 所有打开的文件都有一个对应的文件描述符。 文件描述符的本质是一个非负整数, 当我们打开一个文件时, 系统会给我们分配一个文件描述符。 当我们对一个文件做读写操作的时候, 我们使用 open 函数返回的这个文件描述符会标识该文件,并将其作为参数传递给 read 或者 write 函数。 在 posix.1 应用程序里面, 文件描述符 0,1,2 分别对应着标准输入, 标准输出, 标准错误。

文件 IO open()

函数int open(const char *pathname, int flags)
int open(const char *pathname, int flags, mode_t mode)
头文件#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
参数 pathname路径和文件名
参数 flags文件打开方式, 可用多个标志位按位或设置
参数 mode权限掩码, 对不同用户和组设置可执行, 读, 写权限, 使用八进制数表示, 此参
数可不写
返回值open()执行成功会返回 int 型文件描述符, 出错时返回-1。
作用通过系统调用, 可以打开文件, 并返回文件描述符

参数 flags 可选标志

O_CREAT
O_EXCL
O_RDONLY
O_WRONLY
O_RDWR
O_APPEND
要打开的文件名不存在时自动创建改文件。
要和 O_CREAT 一起使用才能生效, 如果文件存在则 open()调用失败。
只读模式打开文件。
只写模式打开文件。
可读可写模式打开文件。
以追加模式打开文件。

O_NONBLOCK 以非阻塞模式打开。
实验代码
可读可写文件 a.c。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
    int fd;
    fd=open("a.c",O_CREAT|O_RDWR,0666);
    if(fd<0)
    {
        printf("open is error\n");
    }
    printf("fd is %d\n",fd);
    return 0;
}

编译运行:
在 Ubuntu 上编译 ,并运行 a.out, 如下图所示:

文件 IO close()

函数int close(int fd)
头文件#include <unistd.h>
参数 fd文件描述符
返回值成功返回 0; 错误返回-1

实验代码:
编写程序, 创建一个可读可写文件, 获取完属性后关闭。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
    int fd;
    fd=open("a.c",O_CREAT|O_RDWR,0666);
    if(fd<0)
    {
        printf("open is error\n");
    }
    printf("fd is %d\n",fd);
    close(fd);
    return 0;
}

编译运行:
在 Ubuntu 上编译 如下图所示:

文件 IO read()

函数ssize_t read(int fd, void *buf, size_t count)
头文件#include <unistd.h>
参数 fd要读的文件描述符
参数 buf缓冲区, 存放读到的内容
参数 count每次读取的字节数
返回值返回值大于 0, 表示读取到的字节数;
等于 0 在阻塞模式下表示到达文件末尾或没有数据可读(EOF) , 并调用阻塞;
等于-1 表示出错, 在非阻塞模式下表示没有数据可读。

实验代码
在程序中打开 a.c 文件, 并读取打印文件内容。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
       printf("open is error\n");
       return -1;
    }  
     printf("fd is %d\n", fd);
     ret = read(fd, buf, 32);
     if (ret < 0)
     {
        printf("read is error\n");
        return -2;
     } 
     printf("buf is %s\n", buf);
     printf("ret is %ld\n", ret);
     close(fd);
     return 0;
}

编译运行:
在 Ubuntu 上编译,运行 a.out,如下图所示:

编辑 a.c 文件, 内容如下图所示:
 

运行 a.out,如下图所示, 成功读取到 a.c 文件中的 hello world!
 

文件 IO write()

函数ssize_t write(int fd, const void *buf, size_t count);
头文件#include <unistd.h>
参数 fd文件描述符;
参数 buf缓存区, 存放将要写入的数据
参数 count每次写入的个数
功能每次从 buf 缓存区拿 count 个字节写入 fd 文件。
返回值大于或等于 0 表示执行成功, 返回写入的字节数;
返回-1 代表出错。

实验代码
在程序中使用 write 函数向标准输出(屏幕) 打印 hello。 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
    int fd;
    char buf[32]={0};
    ssize_t ret;
    fd=open("a.c",O_CREAT|O_RDWR,0666);
    if(fd<0)
    {
         printf("open is error\n");
         return -1;
    } 
    write(1,"hello\n",6);
    close(fd);
    return 0;
}

编译程序并运行 a.out ,如下图所示, 向标准输出(屏幕) 写入 hello。

在程序中使用 write 函数向文件写入 hello。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
    int fd;
    char buf[32]={0};
    ssize_t ret;
    fd=open("a.c",O_CREAT|O_RDWR,0666);
    if(fd<0)
    {
         printf("open is error\n");
         return -1;
    }
    write(fd,"hello\n",6);
    close(fd);
    return 0;
}

 运行测试
编译运行打开 a.out,并且查看写入的文件 a.c,如下图所示, a.c 文件成功写入 hello。

文件 IO lseek()
         所有打开的文件都有一个当前文件偏移量(current file offset) , 以下简称为 cfo。 cfo 通常是一个非负整数, 用于表明文件开始处到文件当前位置的字节数。 读写操作通常开始于 cfo, 并且使 cfo 增大, 增量为读写的字节数。 文件被打开时, cfo 会被初始化为 0, 除非使用了 O_APPEND 。 使用 lseek 函数可以改变文件的 cfo 。

函数定义off_t lseek(int fd, off_t offset, int whence);
头文件#include <sys/types.h>
#include <unistd.h>
参数 fd文件描述符
参数 off_t offset偏移量, 单位是字节的数量, 可以正负, 如果是负值表示向前移动; 如果是正值,
表示向后移动。
参数 whence当前位置的基点, 可以使用以下三组值。
SEEK_SET: 相对于文件开头
SEEK_CUR:相对于当前的文件读写指针位置
SEEK_END:相对于文件末尾
功能移动文件读写指针; 获取文件长度; 拓展文件空间。
返回值成功返回当前位移, 失败返回-1

举个例子
 把文件位置指针设置为 100 lseek(fd,100,SEEK_SET);
 把文件位置设置成文件末尾 lseek(fd,0,SEEK_END);
 确定当前的文件位置 lseek(fd,0,SEEK_CUR);
实验代码
在程序中使用 lseek 函数移动文件读写位置。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
        printf("open is error\n");
        return -1;
    }
    printf("fd is %d\n", fd);
    ret = read(fd, buf, 32);
    if (ret < 0)
    {
        printf("read is error\n");
        return -2;
    } 
    printf("buf is %s\n", buf);
    printf("ret is %ld\n", ret);
    lseek(fd,0,SEEK_SET);
    ret = read(fd, buf, 32);
    printf("ret is %ld\n", ret);
    close(fd);
    return 0;
}

运行测试
编译运行打开 a.out ,a.c 里面里面有 hello world! , 当使用 lseek 函数移动读写位置时, 再次读 a.c 文件的内容, 依旧可以读到 a.c 的内容, 如下图所示:

 实验代码
在程序中读 a.c 文件的 2 字节, 使用 lseek 函数确定文件的当前位置。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
        printf("open is error\n");
        return -1;
    }

    ret = read(fd, buf, 2);
    if (ret < 0)
    {
        printf("read is error\n");
        return -2;
    }
    printf("buf is %s\n", buf);
    printf("ret is %ld\n", ret);
    ret=lseek(fd,0,SEEK_CUR);
    printf("ret is %ld\n", ret);
    close(fd);
    return 0;
}

运行测试
编译运行打开 a.out ,a.c 里面里面有 hello world! 运行结果如下图所示:

实验代码
在程序中读 a.c 文件, 使用 lseek 函数确定文件的长度。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
        printf("open is error\n");
        return -1;
    }
    ret = read(fd, buf, 2);
    if (ret < 0)
    {
        printf("read is error\n");
        return -2;
    }
    printf("buf is %s\n", buf);
    printf("ret is %ld\n", ret);
    ret=lseek(fd,0,SEEK_END);
    printf("ret is %ld\n", ret);
    close(fd);
    return 0;
}

 运行测试
编译运行打开 a.out ,a.c 里面里面有 hello world! 运行结果如下图所示:

 

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

木士易

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

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

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

打赏作者

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

抵扣说明:

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

余额充值