文件IO系统调用

文件I/O的含义

文件 I/O(输入/输出)是计算机程序中的重要概念,涉及到与文件的读取和写入操作。在C语言中,使用标准库函数来进行文件 I/O 操作。

文件和文件描述符

1.文件拓展名

· .tar,.tar.gz,.tgz,.zip,.tar.bz表示压缩文件,创建命令为tar,gzip,unzip等;

· .sh表示shell脚本文件;

· .pl表示perl语言文件;

· .py表示Python语言文件;

· .conf表示系统服务的配置文件;

· .c表示C文件;

· .h表示头文件;

· .cpp表示C++源文件;

· .so表示动态库文件;

· .a表示静态库文件;

2.文件类型

通过ls -l 命令查看文件类型

文件类型标识文件类型
 -普通文件
d目录文件
l符号链接
c字符设备
b块设备
p管道
s套接字socket

3.文件描述符(file descriptor,fd)

文件描述符是在Unix-like操作系统中用于标识已打开文件或I/O设备的整数。在C语言中,文件描述符是通过int类型的变量表示的。POSIX标准要求每次打开文件时必须使用当前进程中最小可用的文件描述符号码,因此第一次打开文件的描述符一定是3。文件描述符通常是非负整数

文件描述符用途POSIX文件描述符标准I/O文件流
0标准输入STDIN_FILENOstdin
1标准输出STDOUT_FILENOstdout
2标准出错STDERR_FILENOstderr

程序编写 

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

#define MSG_STR "Hello World\n"

int main(int argc, char **argv) {
    // 使用 printf 函数向 stdout 打印字符串
    printf("%s", MSG_STR);
    
    // 使用 fputs 函数向 stdout 写入字符串
    fputs(MSG_STR, stdout);
    
    // 使用 write 函数向 stdout 写入字符串
    write(STDOUT_FILENO, MSG_STR, strlen(MSG_STR));

    return 0;
}
  

  • printf("%s", MSG_STR);:使用 printf 函数向标准输出打印格式化字符串。%s 是一个占位符,表示字符串,用于接收 MSG_STR 的值。

  • fputs(MSG_STR, stdout);:使用 fputs 函数将字符串 MSG_STR 写入到标准输出流 stdout

  • write(STDOUT_FILENO, MSG_STR, strlen(MSG_STR));:使用 write 函数直接向文件描述符 STDOUT_FILENO 写入字符串。这是一个较底层的系统调用,直接操作文件描述符。

最后,#define MSG_STR "Hello World\n" 定义了一个宏,用于表示要输出的字符串 "Hello World\n",这样在代码中多次使用 MSG_STR 就不需要写整个字符串了。

4.文件I/O操作

程序编写

        以下示例程序将调用open()系统调用打开/创建text.txt的文件,然后再调用write()系统调用将字符串MSG_STR写入到文件中,之后在调用read()系统调用读取text.txt文件中的内容并打印;

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

#define BUFSIZE 1024
#define MSG_STR "Hello World\n"

int main(int argc, char *argv[]) {
    int fd = -1;
    int rv = -1;
    char buf[BUFSIZE];

    // 打开文件 test.txt,如果不存在则创建,以读写方式打开,权限为 0666
    fd = open("test.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);

    // 检查文件是否成功打开
    if (fd < 0) {
        perror("Open/Create file test.txt failure");
        return 1;
    }

    printf("Open file returned file descriptor [%d]\n", fd);

    // 将字符串 MSG_STR 写入文件
    if ((rv = write(fd, MSG_STR, strlen(MSG_STR))) < 0) {
        printf("Write %d bytes into file failure: %s\n", rv, strerror(errno));
        goto cleanup;
    }

    // 将文件指针移动到文件开头
    lseek(fd, 0, SEEK_SET);

    // 读取文件内容到缓冲区
    memset(buf, 0, sizeof(buf));
    if ((rv = read(fd, buf, sizeof(buf))) < 0) {
        printf("Read data from file failure: %s\n", strerror(errno));
        goto cleanup;
    }
    printf("Read %d bytes data from file: %s\n", rv, buf);

cleanup:
    // 关闭文件
    close(fd);
    return 0;
}

  • open("test.txt", O_RDWR | O_CREAT | O_TRUNC, 0666):打开文件 "test.txt",如果不存在则创建,以读写方式打开,权限为 0666。O_RDWR 表示读写模式,O_CREAT 表示如果文件不存在则创建,O_TRUNC 表示清空文件内容,0666 是文件权限。

  • write(fd, MSG_STR, strlen(MSG_STR)):将字符串 MSG_STR 写入到文件中。

  • lseek(fd, 0, SEEK_SET):将文件指针移动到文件开头,准备读取文件内容。

  • read(fd, buf, sizeof(buf)):从文件中读取内容到缓冲区 buf

出错处理

概述

        系统调用出错的原因是以整形值的形式保存在errno中,整形值的形式不友好,所以通常将errno的值转成字符串的形式。经常用到的函数:perror()和strerror()

perror():后面只需要跟一个字符串参数s即可,它会将字符串打印在标准输出上,内容是:字符串s后面紧跟着冒号和字符串形式错误的原因;

 缺点:错误只能打印在标准输出上,对于要进行格式化控制的输出或想写入到日志文件中时就不能处理;

strerror():用来将整形值错误errno换装成为字符串形式;

函数原型
void perror(const char *s)

char *strerror(int errno)
程序示例 
 
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <unistd.h>

int main(int argc,char **argv)
{
        char *file_name = "/test.txt";//根目录下不存在 打开会失败
        int fd = -1;

        fd = open(file_name,O_RDONLY,066);//打开文件,权限只读

        if(fd<0)
        {
                perror("Open file failure");

                printf("Open file %s failure:%s\n",file_name,strerror(errno));

                return 0;
        }



        close(fd);
}

 

5. 文件I/O操作函数

(1).open()系统调用

open()函数是一个用于打开文件的系统调用,用于创建或打开一个文件,并返回文件描述符(file descriptor)。在C语言中,该函数通常是通过 fcntl.h 头文件提供的。

以下是 open() 函数的基本原型:

#include <fcntl.h> int open(const char *pathname, int flags, mode_t mode); 

  • pathname:要打开或创建的文件的路径名。
  • flags:打开文件的标志,可以是以下之一或它们的组合:
    • O_RDONLY:只读方式打开。
    • O_WRONLY:只写方式打开。
    • O_RDWR:读写方式打开。
    • O_CREAT:如果文件不存在则创建。
    • O_TRUNC:如果文件存在并且以写入方式打开,则将其长度截断为0。
    • O_APPEND:以追加方式打开。
    • 等等,还有其他标志。
  • mode:创建文件时的权限,通常是一个八进制数,例如 0666

返回值是一个非负整数的文件描述符,如果出现错误,则返回 -1 并设置全局变量 errno

(2)create()系统调用

在早期的Unix系统中,create 函数是用于创建新文件的系统调用。然而,随着时间的推移,这个函数逐渐被 open 函数取代,open 函数提供了更多的灵活性。

create 函数的原型如下:

#include <fcntl.h>

int create(const char *pathname, mode_t mode);

在这里,pathname 是新文件的路径名,mode 是新文件的权限。

(3)close()系统调用

close() 函数是用于关闭文件描述符的系统调用。在C语言中,这个函数是通过 unistd.h 头文件提供的。以下是 close() 函数的基本原型:

#include <unistd.h>

int close(int fd);

 

  • fd:要关闭的文件描述符。

close() 函数的返回值是一个整数,成功关闭文件返回0,失败返回-1,并设置全局变量 errno 来指示错误的原因。

(4)write()系统调用

write() 函数是一个用于向文件描述符写入数据的系统调用。在C语言中,这个函数是通过 unistd.h 头文件提供的。以下是 write() 函数的基本原型:

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • fd:要写入的文件描述符。
  • buf:包含要写入的数据的缓冲区的指针。
  • count:要写入的字节数。

write() 函数返回一个 ssize_t 类型的值,表示实际写入的字节数。如果出现错误,返回值为 -1,并设置全局变量 errno 来指示错误的原因。

(5)Iseek()系统调用

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
  • fd:文件描述符。
  • offset:偏移量,表示相对于 whence 参数的位置。
whence位置
SEEK_SET文件头
SEEK_CUR当前位置
SEEK_END文件尾

例:

        Iseek(fd,0,SEEK_SET):   将文件偏移量设置到文件开始的第一个字节上;

        Iseek(fd,0,SEEK_END):   将文件偏移量设置到文件最后一个字节上;

        Iseek(fd,-1,SEEK_END):  将文件偏移量设置到文件最后的倒数第一个字节上;

 我们再从文件中读取内容,或者往文件中写内容时都有一个起始地址,这个起始地址就是文件偏移量,当我们对文件进行读写的时候都是从这个文件偏移量开始。

(6)read系统调用

read() 是一个用于从文件描述符中读取数据的系统调用。在C语言中,该函数是通过 unistd.h 头文件提供的。以下是 read() 函数的基本原型:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

read() 是一个用于从文件描述符中读取数据的系统调用。在C语言中,该函数是通过 unistd.h 头文件提供的。以下是 read() 函数的基本原型:

  • fd:要读取的文件描述符。
  • buf:包含读取数据的缓冲区的指针。
  • count:要读取的字节数。

read() 函数返回一个 ssize_t 类型的值,表示实际读取的字节数。如果返回值为 0,表示已经到达文件末尾。如果返回值为 -1,表示发生错误,并且 errno 变量被设置以指示错误的类型。

(7)dup()和dup2()系统调用

dup()dup2() 是用于复制文件描述符的系统调用,通常在文件 I/O 操作中使用。它们的作用是创建一个新的文件描述符,该描述符与现有的文件描述符指向同一个文件表项。

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char **argv)
{
        int fd = -1;
        fd = open("std.txt",O_RDWR|O_CREAT|O_TRUNC,0666);

        if(fd<0)
        {
                printf("Open file failure:%s\n",strerror(errno));
                return 0;
        }

        dup2(fd,STDIN_FILENO);
        dup2(fd,STDOUT_FILENO);
        dup2(fd,STDERR_FILENO);

        printf("fd = %d\n",fd);
        close(fd);
}

 

6.文件夹操作相关系统调用 

 

函数原型函数说明
int mkdir(const char *pathname,mode_t,mode)创建文件夹
int remdir(const char  *pathname)删除文件夹
DIR *opendir(const char *pathname)打开文件夹
struct dirent *readdir(DIR *dp)读文件夹
int closedir(IDR  *dp)关闭文件夹
int chdir(const char  *pathname)改变工作目录
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<errno.h>
#include<sys/stat.h>
#include<sys/types.h>
#include <unistd.h>
 
#include <fcntl.h>


#define TEST_DIR "dir"

int main(int argc,char **argv)

{
        int                rv;
        int                fd1;
        int                fd2;
        DIR                *dirp = NULL;

        struct dirent      *direntp = NULL;
        struct dirent      b;
        /*指针初始化*/
        int a;



        printf("1\n");
        /*创建文件夹dir,并设置文件夹权限为755*/
        if(a = (mkdir(TEST_DIR, 0755)) < 0)
        {
                printf("a:%d\n", a);

                printf("2\n");
                printf("create directory %s failure : %s\n", TEST_DIR, strerror(errno));
                return -1;
        }


        printf("mkdir successfully!\n");
        /*更改当前工作路径到文件夹dir下去*/
        if(chdir(TEST_DIR)<0)
        {
                printf("Change directory to '%s' failure : %s\n",TEST_DIR,strerror(errno));
                rv = -2;
                goto cleanup;
        }

        printf("chdir successfully!\n");
        /*在dir文件夹下创建普通文本文件file1.txt,并设置权限为644*/
        if(fd1 = creat("file1.txt",0644)<0)
        {
                printf("Creat file1.txt failure : %s\n",strerror(errno));
                rv = -3;
                goto cleanup;


        }



        /*在dir文件夹下创建file2.txt,并设置文件权限为644*/
        if(fd2 = creat("file2.txt",0644)<0)
        {
                printf("Creat file1.txt failure : %s\n",strerror(errno));
                rv = -4;
                goto cleanup;
        }
        printf("create successfully!\n");

        /*更改当前工作路径到父目录*/
        if(chdir("../") < 0)
        {
                printf("Change directory to '%s' failure : %s\n",TEST_DIR,strerror(errno));
                rv = -5;
                goto cleanup;
        }
        printf("chdir successfully!\n");


        /*打开dir文件夹*/
        if((dirp = opendir(TEST_DIR)) == NULL)
        {
                rv = -6;
                printf("opendir '%s' error : %s\n",TEST_DIR,strerror(errno));
                goto cleanup;
        }

        printf("opendir successfully!\n");

        /*lie出dir文件夹里面的所有文件和文件夹*/
        while((direntp = readdir(dirp)) != NULL)
        {
                printf("Find file : %s\n",direntp -> d_name);
        }

        /*关闭所有打开的文件夹*/
        closedir(dirp);

cleanup:

        if(fd1 >= 0)
        {
                close(fd1);
        }

        if(fd2 >= 0)
        {
                close(fd2);
        }




}

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值