Linux应用编程学习-文件IO

1、文件IO

①函数原型
  • open函数
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode); /* mode 文件权限 */

open函数部分flags分析:

**O_CREAT、O_EXCL:**O_CREAT是创建文件,如果文件已经存在则会重新创建,原来的内容都会被丢弃。而O_EXCL和O_CREAT一起使用的话,如果文件存在,则会返回错误。mode_t mode 这个参数是创建文件时的权限是可以指定的。

如 mode = 666 ; 则代表这个文件的所有者,所属组,其他人都是可读可写(rw),但都没有执行的权限(x).

Linux 系统中,文件的基本权限由 9 个字符组成,以 rwxrw-r-x 为例,我们可以使用数字来代表各个权限,各个权限与数字的对应关系如下:

r --> 4
w --> 2
x --> 1

由于这 9 个字符分属 3 类用户,因此每种用户身份包含 3 个权限(r、w、x),通过将 3 个权限对应的数字累加,最终得到的值即可作为每种用户所具有的权限。

拿 rwxrw-r-x 来说,所有者、所属组和其他人分别对应的权限值为:

所有者 = rwx = 4+2+1 = 7
所属组 = rw- = 4+2 = 6
其他人 = r-x = 4+1 = 5

所以,此权限对应的权限值就是 765。

O_APPEND 、O_TRUNC : O_APPEND是在文件原来内容的后面添加新的内容,O_TRUNC是把文件原来的内容全部丢弃,再写入新的内容。

  • read函数
ssize_t read(int fd, void *buf, size_t count);
  • write函数
ssize_t write(int fd, const void *buf, size_t count);
  • close函数
int close(int fd);
  • lseek函数:更改文件指针(光标)
off_t lseek(int fd, off_t offset, int whence);
fd:文件描述符
offset:偏移量
whence:光标的位置 SEEK_SET(文件头)、SEEK_CUR(当前位置)、SEEK_END(文件尾)
/*********************************************************************************
 * 文件名:lseek.c
 * 功  能:使用lseek()来计算一个文件的长度
 * 作  者:FENG
**********************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int fd = -1; //文件描述符
    int ret = -1;

     /* 0、判断是否指定文件名 */
    if (argc < 2)
    {
        printf("usage: %s filename!\n", argv[0]); 
        return -1;
    }

    /* 1、打开文件 */
    fd = open(argv[1], O_RDWR); 
    if (fd < 0)
    {
        printf("打开文件失败!\n");
        return -1;
    }
    /* 2、移动文件光标 */
    ret = lseek(fd, 0, SEEK_END); //把光标移动到文件末尾
    printf("文件长度为:%d\n", ret);

    close(fd);

    return 0;
}
  • dup函数
int dup(int oldfd);
int dup2(int oldfd, int newfd);

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>
int dup3(int oldfd, int newfd, int flags);
②简单使用示例代码
/*********************************************************************************
 * 文件名:file.c
 * 功  能:文件IO使用示例
 * 作  者:FENG
**********************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    int fd = -1; //文件描述符
    int ret = -1;
    char w_buf[20] = "hello world!";
    char r_buf[20] = ""; 
    /* 1、打开文件 */
    fd = open("a.txt", O_RDWR | O_CREAT | O_EXCL, 0666); //如果文件不存在就创建,权限为666
    if (fd < 0)
    {
        printf("打开文件失败!\n");
        return -1;
    }

    /* 2、写文件 */
    ret = write(fd, w_buf, strlen(w_buf));
    if (ret < 0)
    {
        printf("写入文件失败!\n");
        return -1;
    }
    printf("写入文件成功!共写入%d个字符!\n", ret);

    /* 3、读文件 */
    //首先,要移动光标到文件开始的位置
    lseek(fd, 0, SEEK_SET);
    ret = read(fd, r_buf, 20);
    if (ret < 0)
    {
        printf("读出文件失败!\n");
    }
    printf("读出文件成功!共读出%d个字符!内容为%s\n", ret, r_buf);
    /* 4、关闭文件 */
    close(fd);
    return 0;   
}

③文件共享

什么是文件共享?实现文件共享有哪些方式?

文件共享就是一个文件被多个文件描述符同时(一个文件描述符打开但未关闭,另一个文件描述符打开文件)进行读写等操作。

三种方式:

a.同一进程open同一个文件,得到不同的文件描述符指向同一个文件。[O_APPEND可以实现接续写/读文件内容]

b.不同进程open同一个文件,得到不同的文件描述符指向同一个文件。

c.dup和dup2来复制文件描述符,得到不同的文件描述符指向同一个文件。[好用的做法]

/*********************************************************************************
 * 文件名:dup.c
 * 功  能:复制文件描述符,实现文件共享
 * 作  者:FENG
**********************************************************************************/

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

int main(void)
{
    int fd = -1, cp_fd = -1;
    int i = 0;
    fd = open("1.txt",  O_RDWR | O_CREAT, 0666);
    if (fd < 0)
    {
        printf("文件打开失败!\n");
    }
    printf("fd = %d\n", fd);
    //cp_fd = dup(fd);        //复制旧fd,因为close(1),所以1->stdout被释放了,根据Linux自动分配机制,由0开始分配。
    cp_fd = dup2(fd, 88);   //dup2相比dup可以指定复制的文件描述符的值
    printf("cp_fd = %d\n", cp_fd);
    for (i = 0; i<10; i++)
    {
        write(fd, "1111", 4);
        write(cp_fd, "2222", 4);
    }
    close(fd);
    return 0;
}
运行的结果:
feng@JFeng:~/linux_app/file_io$ gcc -o dup dup.c
feng@JFeng:~/linux_app/file_io$ ls
2.txt  dup  dup.c  file  file.c  lseek  lseek.c  stdout  stdout.c
feng@JFeng:~/linux_app/file_io$ ./dup
fd = 3
cp_fd = 88
feng@JFeng:~/linux_app/file_io$ ls
1.txt  2.txt  dup  dup.c  file  file.c  lseek  lseek.c  stdout  stdout.c
feng@JFeng:~/linux_app/file_io$ cat 1.txt
11112222111122221111222211112222111122221111222211112222111122221111222211112222
feng@JFeng:~/linux_app/file_io$
④重定位标准输出(stdout)
/*********************************************************************************
 * 文件名:stdout.c
 * 功  能:使用dup()来重定位stdout(标准输出)
 * 作  者:FENG
**********************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    int fd = -1, cp_fd = -1;
    fd = open("1.txt",  O_RDWR | O_CREAT, 0666);
    if (fd < 0)
    {
        printf("文件打开失败!\n");
    }
    printf("fd = %d\n", fd);
    close(1); //关闭标准输出设备文件,0->stdin,1->stdout,2->stderr,
    cp_fd = dup(fd); //复制旧fd,因为close(1),所以1->stdout被释放了,根据Linux自动分配机制,由0开始分配。
    printf("cp_fd = %d\n", cp_fd);
    printf("这里已经重定位stdout成功了!\n");
    close(fd);
    return 0;
}

运行结果:

feng@JFeng:~/linux_app/file_io$ ls
a.txt  dup.c  file  file.c  lseek  lseek.c  stdout.c
feng@JFeng:~/linux_app/file_io$ gcc -o stdout stdout.c
feng@JFeng:~/linux_app/file_io$ ls
a.txt  dup.c  file  file.c  lseek  lseek.c  stdout  stdout.c
feng@JFeng:~/linux_app/file_io$ ./stdout
fd = 3
feng@JFeng:~/linux_app/file_io$ ls
1.txt  a.txt  dup.c  file  file.c  lseek  lseek.c  stdout  stdout.c
feng@JFeng:~/linux_app/file_io$ cat 1.txt
cp_fd = 1
这里已经重定位stdout成功了!
feng@JFeng:~/linux_app/file_io$

命令行重定位,返回信息写入文件中:

feng@JFeng:~/linux_app/file_io$ ls
dup.c  file  file.c  lseek  lseek.c  stdout  stdout.c
feng@JFeng:~/linux_app/file_io$ ls -la > 2.txt
feng@JFeng:~/linux_app/file_io$ ls
2.txt  dup.c  file  file.c  lseek  lseek.c  stdout  stdout.c
feng@JFeng:~/linux_app/file_io$ cat 2.txt
total 60
drwxr-xr-x 1 feng feng 4096 Feb 27 00:42 .
drwxr-xr-x 1 feng feng 4096 Feb 26 21:21 ..
-rw-r--r-- 1 feng feng    0 Feb 27 00:42 2.txt
-rw-r--r-- 1 feng feng    0 Feb 27 00:01 dup.c
-rwxr-xr-x 1 feng feng 8656 Feb 26 22:33 file
-rw-r--r-- 1 feng feng 1351 Feb 27 00:01 file.c
-rwxr-xr-x 1 feng feng 8472 Feb 26 22:27 lseek
-rw-r--r-- 1 feng feng  950 Feb 26 22:33 lseek.c
-rwxr-xr-x 1 feng feng 8472 Feb 27 00:25 stdout
-rw-r--r-- 1 feng feng  902 Feb 27 00:25 stdout.c
feng@JFeng:~/linux_app/file_io$
⑤标准IO
  • 标准IO库函数与文件IO(API)有什么不同?标准IO更具有移植性,其实就是在文件IO的基础上再做了一层封装,效率更高,易用性更好。

  • 函数原型

    FILE *fopen(const char *pathname, const char *mode);
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
    int fclose(FILE *stream);
    int fseek(FILE *stream, long offset, int whence);
    
  • 一些对比

    fopen() modeopen() flags
    rO_RDONLY
    wO_WRONLY | O_CREAT | O_TRUNC
    aO_WRONLY | O_CREAT | O_APPEND
    r+O_RDWR
    w+O_RDWR | O_CREAT | O_TRUNC
    a+O_RDWR | O_CREAT | O_APPEND
/*********************************************************************************
 * 文件名:std_io.c
 * 功  能:标准IO库函数使用示例
 * 作  者:FENG
**********************************************************************************/
#include <stdio.h>


int main(void)
{
    FILE *fp = NULL;
    size_t len = -1;
    char w_buf[20] = "hello world!"; 
    char r_buf[20] = {0}; 
    /* 1、打开文件 */
    fp = fopen("a.txt", "w+");
    if (fp == NULL)
    {
        printf("打开文件失败!\n");
        return -1;
    }
    /* 2、写文件 */
    len = fwrite(w_buf, sizeof(char), sizeof(w_buf)/sizeof(w_buf[0]), fp);
    if (len < 0)
    {
        printf("写文件失败!\n");
    }
    printf("写文件成功,写入%ld字节,内容是%s\n", len, w_buf);
    /* 3、读文件 */
    //首先,要移动一下光标
    fseek(fp, 0, SEEK_SET);
    len = fread(r_buf, sizeof(char), sizeof(r_buf)/sizeof(r_buf[0]), fp);
    if (len < 0)
    {
        printf("读文件失败!\n");
    }
    printf("读文件成功,读出%ld字节,内容是%s\n", len, r_buf);

    /* 4、打开文件 */
    fclose(fp);

    return 0;
}

⑥补充说明
  • 文件描述符:文件描述符就是由Linux系统自动分配的,既然是系统分配的那就遵循一定的规律,其实文件描述符是由数组来进行管理的文件描述符表,inode就是描述符指针,value就是那个数值。其实0,1,2已经被系统使用,分别对应stdin、stdout、stderr。我们使用open打开的最小的文件描述符是3。
  • man手册:可以查询命令、API、函数 详细信息。
    • man 1 命令 :查询命令 man 1 ls
    • man 2 API : 查询API 如 man 2 open
    • man 3 函数 :查询函数 如man 3 memset
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值