首页 > 系统相关 >Linux系统编程-文件相关操作使用详解

Linux系统编程-文件相关操作使用详解

时间:2024-07-09 22:28:52浏览次数:16  
标签:printf 文件 编程 描述符 详解 fd file Linux close

1.文件描述符

文件描述符(File Descriptor)是操作系统中用于访问和操作文件或输入输出资源的一个抽象指针。它是一个非负整数,标识一个已经打开的文件或输入输出资源(如管道、网络连接等)。在UNIX和类UNIX系统(如Linux)中,文件描述符是非常重要的概念,用于文件操作、进程间通信、网络编程等多个方面。

文件描述符的基本概念

  1. 文件描述符的类型

    • 标准输入(Standard Input): 文件描述符为0,通常与键盘关联,用于从用户处读取输入。
    • 标准输出(Standard Output): 文件描述符为1,通常与屏幕关联,用于向用户显示输出。
    • 标准错误(Standard Error): 文件描述符为2,通常也与屏幕关联,用于显示错误信息。
  2. 文件描述符的作用

    • 文件操作: 文件描述符用于读取、写入文件和控制文件状态。常用的系统调用如 open(), read(), write(), close() 等都使用文件描述符。
    • 进程间通信: 通过管道(pipe)或命名管道(FIFO)等机制,文件描述符用于在进程间传递数据。
    • 网络编程: 套接字(socket)也被视为文件,文件描述符用于处理网络连接。

2.对文件描述符的操作

1.打开和关闭文件

1.open()

open() 会打开一个文件 (可能创建文件),并返回一个新的文件描述符。
原型1:
int open(const char *pathname, int flags);
pathname: 文件路径。
flags: 文件打开的标志,如 O_RDONLY(只读),O_WRONLY(只写),O_RDWR(读写),O_CREAT(如果文件不存在则创建),O_EXCL(与 O_CREAT 一起使用,如果文件已存在则失败)。
原型2:
int open(const char *pathname, int flags, mode_t mode);
mode: 文件权限(仅在创建文件时使用),如 S_IRUSR(用户读权限),S_IWUSR(用户写权限)。

2.close()

close() 系统调用用于关闭一个文件描述符,使其不再指向任何文件,并释放相关资源。

int close(int fd);
fd: 文件描述符。

示例代码:

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

int main() {
    int fd;
    const char *filepath = "example.txt";

    // 尝试打开文件
    fd = open(filepath, O_RDONLY);
    if (fd == -1) {
        // 打开文件失败,打印错误信息并退出
        perror("Failed to open file");
        return 1;
    }
    printf("File opened successfully.\n");

    // 关闭文件
    if (close(fd) == -1) {
        // 关闭文件失败,打印错误信息
        perror("Failed to close file");
        return 1;
    }
    printf("File closed successfully.\n");

    return 0;
}

2.读写文件

在Linux系统编程中,read()write() 系统调用用于文件的读写操作。这些调用操作文件描述符,并在底层实现文件内容的读取和写入。

1.read()

原型
ssize_t read(int fd, void *buf, size_t count);
参数:
fd: 文件描述符,表示要读取的文件。
buf: 缓冲区指针,用于存储读取的数据。
count: 需要读取的字节数。
返回值:
成功时返回读取的字节数,返回值为0表示已到达文件末尾。
失败时返回-1,并设置 errno。

2.write()

原型:
ssize_t write(int fd, const void *buf, size_t count);
参数:
fd: 文件描述符,表示要写入的文件。
buf: 缓冲区指针,包含要写入的数据。
count: 需要写入的字节数。
返回值:
成功时返回写入的字节数。
失败时返回-1,并设置 errno。

示例代码:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#define BUFFER_SIZE 1024

int main() {
    int source_fd, dest_fd;
    ssize_t bytes_read, bytes_written;
    char buffer[BUFFER_SIZE];

    // 打开源文件 example.txt 以只读方式
    source_fd = open("example.txt", O_RDONLY);
    if (source_fd == -1) {
        perror("Failed to open source file");
        return 1;
    }
    printf("Source file opened successfully.\n");

    // 创建并打开目标文件 copy.txt 以只写方式,如果不存在则创建
    // 文件权限使用数字形式指定:0600 表示用户读写权限
    dest_fd = open("copy.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600);
    if (dest_fd == -1) {
        perror("Failed to open destination file");
        close(source_fd);
        return 1;
    }
    printf("Destination file opened successfully.\n");

    // 从源文件读取内容并写入目标文件
    while ((bytes_read = read(source_fd, buffer, BUFFER_SIZE)) > 0) {
        bytes_written = write(dest_fd, buffer, bytes_read);
        if (bytes_written != bytes_read) {
            perror("Failed to write to destination file");
            close(source_fd);
            close(dest_fd);
            return 1;
        }
    }

    if (bytes_read == -1) {
        perror("Failed to read from source file");
    } else {
        printf("File copy completed successfully.\n");
    }

    // 关闭文件
    if (close(source_fd) == -1) {
        perror("Failed to close source file");
        return 1;
    }
    printf("Source file closed successfully.\n");

    if (close(dest_fd) == -1) {
        perror("Failed to close destination file");
        return 1;
    }
    printf("Destination file closed successfully.\n");

    return 0;
}

3.文件定位

1.lseek()

lseek() 系统调用用于移动文件描述符的读写位置。它允许程序在文件中任意移动读写位置,而不仅仅是顺序读写。

原型:
off_t lseek(int fd, off_t offset, int whence);
参数:
fd: 文件描述符,表示要操作的文件。
offset: 偏移量,表示从 whence 开始的偏移字节数。
whence: 定位基准,决定偏移量的参考位置。可以是以下值之一:
SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件末尾
返回值:
成功时返回新的文件偏移量(以字节为单位)。
失败时返回 -1,并设置 errno。

示例代码:

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

int main() {
    int fd;
    off_t offset;
    const char *filepath = "example.txt";
    char buffer[20];

    // 打开文件 example.txt 以读写方式
    fd = open(filepath, O_RDWR);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }
    printf("File opened successfully.\n");

    // 将文件偏移量移动到文件开头的第10个字节处
    offset = lseek(fd, 10, SEEK_SET);
    if (offset == -1) {
        perror("Failed to lseek");
        close(fd);
        return 1;
    }
    printf("File offset moved to: %ld\n", (long)offset);

    // 从新的偏移位置读取数据
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
    if (bytes_read == -1) {
        perror("Failed to read file");
        close(fd);
        return 1;
    }

    // 确保缓冲区以null字符结束
    buffer[bytes_read] = '\0';
    printf("Read data: %s\n", buffer);

    // 将文件偏移量移动到文件末尾再向前移动10个字节
    offset = lseek(fd, -10, SEEK_END);
    if (offset == -1) {
        perror("Failed to lseek");
        close(fd);
        return 1;
    }
    printf("File offset moved to: %ld\n", (long)offset);

    // 写入新数据到新的偏移位置
    const char *new_data = "New Data";
    ssize_t bytes_written = write(fd, new_data, strlen(new_data));
    if (bytes_written == -1) {
        perror("Failed to write file");
        close(fd);
        return 1;
    }
    printf("Wrote %ld bytes: %s\n", (long)bytes_written, new_data);

    // 关闭文件
    if (close(fd) == -1) {
        perror("Failed to close file");
        return 1;
    }
    printf("File closed successfully.\n");

    return 0;
}

4.文件系统同步

1.fsync()

fsync() 用于将指定文件描述符的所有修改数据同步到存储设备上。它确保文件内容和元数据(如文件权限、修改时间等)被写入磁盘。

原型:
int fsync(int fd);
参数:
fd: 文件描述符。
返回值:
成功时返回0。
失败时返回-1,并设置 errno。

2.fdatasync()

fdatasync() 类似于 fsync(),但只保证文件内容(数据)同步到存储设备上,不包括文件元数据的同步(除非元数据对文件内容的写入有影响)。

原型:
int fdatasync(int fd);
参数:
fd: 文件描述符。
返回值:
成功时返回0。
失败时返回-1,并设置 errno.

3.ftruncate()

ftruncate() 用于将指定文件描述符的文件大小截断为指定长度。如果文件比新长度短,则扩展文件;如果文件比新长度长,则截断文件。

原型:
int ftruncate(int fd, off_t length);
参数:
fd: 文件描述符。
length: 新的文件大小(字节数)。
返回值:
成功时返回0。
失败时返回-1,并设置 errno。

示例代码:

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

#define FILE_PATH "example.txt"

int main() {
    int fd;
    const char *data = "Hello, World!";
    ssize_t bytes_written;

    // 打开文件 example.txt 以读写方式,如果不存在则创建
    fd = open(FILE_PATH, O_RDWR | O_CREAT, 0644);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }
    printf("File opened successfully.\n");

    // 写入数据到文件
    bytes_written = write(fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("Failed to write to file");
        close(fd);
        return 1;
    }
    printf("Wrote %ld bytes to the file.\n", (long)bytes_written);

    // 使用 fsync() 同步文件数据和元数据
    if (fsync(fd) == -1) {
        perror("Failed to fsync file");
        close(fd);
        return 1;
    }
    printf("File data and metadata synchronized using fsync().\n");

    // 截断文件到 5 个字节
    if (ftruncate(fd, 5) == -1) {
        perror("Failed to truncate file");
        close(fd);
        return 1;
    }
    printf("File truncated to 5 bytes.\n");

    // 使用 fdatasync() 同步文件数据
    if (fdatasync(fd) == -1) {
        perror("Failed to fdatasync file");
        close(fd);
        return 1;
    }
    printf("File data synchronized using fdatasync().\n");

    // 关闭文件
    if (close(fd) == -1) {
        perror("Failed to close file");
        return 1;
    }
    printf("File closed successfully.\n");

    return 0;
}


5.文件状态

1.fstat()

fstat() 系统调用用于获取与文件描述符关联的文件的状态信息。该系统调用返回文件的各种属性,包括文件大小、权限、最后访问时间等。

原型:
int fstat(int fd, struct stat *statbuf);
参数:
fd: 文件描述符,表示要获取状态信息的文件。
statbuf: 指向 stat 结构体的指针,该结构体用于存储文件的状态信息。
返回值:
成功时返回0。
失败时返回-1,并设置 errno。

stat 结构体

stat 结构体定义在 <sys/stat.h> 头文件中,包含许多字段,以下是一些常用字段:

struct stat {
    dev_t     st_dev;     // 文件所在设备的ID
    ino_t     st_ino;     // inode号
    mode_t    st_mode;    // 文件类型和权限
    nlink_t   st_nlink;   // 硬链接数
    uid_t     st_uid;     // 所有者的用户ID
    gid_t     st_gid;     // 所有者的组ID
    dev_t     st_rdev;    // 设备ID(如果是特殊文件)
    off_t     st_size;    // 文件大小(以字节为单位)
    blksize_t st_blksize; // 文件系统I/O块大小
    blkcnt_t  st_blocks;  // 分配的块数
    time_t    st_atime;   // 最后访问时间
    time_t    st_mtime;   // 最后修改时间
    time_t    st_ctime;   // 最后状态改变时间
};

示例代码:

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

int main() {
    int fd;
    struct stat statbuf;
    const char *filepath = "example.txt";

    // 打开文件 example.txt 以只读方式
    fd = open(filepath, O_RDONLY);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }
    printf("File opened successfully.\n");

    // 获取文件状态
    if (fstat(fd, &statbuf) == -1) {
        perror("Failed to get file status");
        close(fd);
        return 1;
    }

    // 打印文件状态信息
    printf("File size: %ld bytes\n", statbuf.st_size);
    printf("Number of blocks allocated: %ld\n", statbuf.st_blocks);
    printf("Block size: %ld bytes\n", statbuf.st_blksize);
    printf("File type and mode: %o\n", statbuf.st_mode);
    printf("Number of hard links: %ld\n", statbuf.st_nlink);
    printf("Owner UID: %d\n", statbuf.st_uid);
    printf("Owner GID: %d\n", statbuf.st_gid);
    printf("Last access time: %s", ctime(&statbuf.st_atime));
    printf("Last modification time: %s", ctime(&statbuf.st_mtime));
    printf("Last status change time: %s", ctime(&statbuf.st_ctime));

    // 关闭文件
    if (close(fd) == -1) {
        perror("Failed to close file");
        return 1;
    }
    printf("File closed successfully.\n");

    return 0;
}

6.文件描述符复制

dup()dup2() 是用于复制文件描述符的系统调用。在Unix和类Unix操作系统中,这些调用用于创建一个新的文件描述符,该描述符指向与原始文件描述符相同的文件表项。

1.dup()

原型:
int dup(int oldfd);
参数:
oldfd: 要复制的文件描述符。
返回值:
成功时返回新的文件描述符。
失败时返回 -1,并设置 errno。

2.dup2()

原型:
int dup2(int oldfd, int newfd);
参数:
oldfd: 要复制的文件描述符。
newfd: 新的文件描述符。如果 newfd 已经被打开,它将首先被关闭。如果 oldfd 和 newfd 相同,则 dup2() 什么也不做,直接返回 newfd。
返回值:
成功时返回 newfd。
失败时返回 -1,并设置 errno。

示例代码:

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

int main() {
    int fd, new_fd, new_fd2;
    const char *filepath = "example.txt";
    const char *data = "Hello, World!";
    ssize_t bytes_written;

    // 打开文件 example.txt 以读写方式,如果不存在则创建
    fd = open(filepath, O_RDWR | O_CREAT, 0644);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }
    printf("File opened successfully with file descriptor %d.\n", fd);

    // 使用 dup() 复制文件描述符
    new_fd = dup(fd);
    if (new_fd == -1) {
        perror("Failed to duplicate file descriptor");
        close(fd);
        return 1;
    }
    printf("File descriptor %d duplicated to %d using dup().\n", fd, new_fd);

    // 使用 dup2() 复制文件描述符到指定的描述符 5
    new_fd2 = dup2(fd, 5);
    if (new_fd2 == -1) {
        perror("Failed to duplicate file descriptor to 5");
        close(fd);
        close(new_fd);
        return 1;
    }
    printf("File descriptor %d duplicated to %d using dup2().\n", fd, new_fd2);

    // 使用新的文件描述符写入数据到文件
    bytes_written = write(new_fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("Failed to write to file using new file descriptor");
        close(fd);
        close(new_fd);
        close(new_fd2);
        return 1;
    }
    printf("Wrote %ld bytes to the file using duplicated file descriptor %d.\n", (long)bytes_written, new_fd);

    // 关闭文件描述符
    if (close(fd) == -1) {
        perror("Failed to close original file descriptor");
        return 1;
    }
    printf("Original file descriptor %d closed successfully.\n", fd);

    if (close(new_fd) == -1) {
        perror("Failed to close duplicated file descriptor");
        return 1;
    }
    printf("Duplicated file descriptor %d closed successfully.\n", new_fd);

    if (close(new_fd2) == -1) {
        perror("Failed to close second duplicated file descriptor");
        return 1;
    }
    printf("Second duplicated file descriptor %d closed successfully.\n", new_fd2);

    return 0;
}

7.文件控制

1.fcntl()

fcntl() 系统调用用于控制文件描述符的一些属性和行为。它提供了多种操作,包括复制文件描述符、获取/设置文件描述符标志、文件状态标志等。

原型:
int fcntl(int fd, int cmd, ... /* arg */ );
参数:
fd: 文件描述符。
cmd: 控制命令,不同的命令要求不同的第三个参数(arg)。
F_DUPFD: 复制文件描述符。
F_GETFD: 获取文件描述符标志。
F_SETFD: 设置文件描述符标志。
F_GETFL: 获取文件状态标志。
F_SETFL: 设置文件状态标志。
F_GETLK, F_SETLK, F_SETLKW: 文件加锁操作。

示例代码:

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

int main() {
    int fd, new_fd, flags;
    const char *filepath = "example.txt";
    const char *data = "Hello, World!";
    ssize_t bytes_written;

    // 打开文件 example.txt 以读写方式,如果不存在则创建
    fd = open(filepath, O_RDWR | O_CREAT, 0644);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }
    printf("File opened successfully with file descriptor %d.\n", fd);

    // 使用 fcntl() 复制文件描述符
    new_fd = fcntl(fd, F_DUPFD, 0);
    if (new_fd == -1) {
        perror("Failed to duplicate file descriptor");
        close(fd);
        return 1;
    }
    printf("File descriptor %d duplicated to %d using fcntl().\n", fd, new_fd);

    // 使用 fcntl() 获取文件状态标志
    flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        perror("Failed to get file status flags");
        close(fd);
        close(new_fd);
        return 1;
    }
    printf("File status flags: %d\n", flags);

    // 添加非阻塞标志并设置回文件状态标志
    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) == -1) {
        perror("Failed to set file status flags");
        close(fd);
        close(new_fd);
        return 1;
    }
    printf("File status flags set to: %d\n", flags);

    // 使用新的文件描述符写入数据到文件
    bytes_written = write(new_fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("Failed to write to file using new file descriptor");
        close(fd);
        close(new_fd);
        return 1;
    }
    printf("Wrote %ld bytes to the file using duplicated file descriptor %d.\n", (long)bytes_written, new_fd);

    // 关闭文件描述符
    if (close(fd) == -1) {
        perror("Failed to close original file descriptor");
        return 1;
    }
    printf("Original file descriptor %d closed successfully.\n", fd);

    if (close(new_fd) == -1) {
        perror("Failed to close duplicated file descriptor");
        return 1;
    }
    printf("Duplicated file descriptor %d closed successfully.\n", new_fd);

    return 0;
}

标签:printf,文件,编程,描述符,详解,fd,file,Linux,close
From: https://blog.csdn.net/qq_42037383/article/details/140305938

相关文章

  • Franak Robot State详解
    机器人状态以1kHz的速率提供机器人传感器读数和估计值。它提供:关节级信号:电机和估计的关节角度及其导数、关节扭矩和导数、估计的外部扭矩、关节碰撞/接触。笛卡尔级信号:笛卡尔位姿、配置的末端执行器和负载参数、作用于末端执行器的外部扳手、笛卡尔碰撞。接口信号:最后的......
  • MongoDB安装、基础操作和聚合实例详解
    虽然MongoDB这些年很流行,但笔者之前没研究过,现在有需求研究这类NoSQL的数据库,是为了验证其是否可被替换。MongoDB是很轻量的文档数据库,简单测试也懒得专门准备虚拟机环境了,直接在macOS上安装测试下其基础功能。1.使用Homebrew安装MongoDB2.启动/停止MongoDB服务3.启动......
  • LAMP万字详解(概念、构建步骤)
    目录LAMPApache起源主要特点软件版本编译安装httpd服务器编译安装的优点操作步骤准备工作编译安装优化执行路径添加服务守护进程配置httpd查看Web站点的访问情况虚拟主机类型部署基于域名的虚拟主机为虚拟主机提供域名解析(两个域名)不同ip访问不同的内容......
  • MongoDB安装、基础操作和聚合实例详解
    虽然MongoDB这些年很流行,但笔者之前没研究过,现在有需求研究这类NoSQL的数据库,是为了验证其是否可被替换。MongoDB是很轻量的文档数据库,简单测试也懒得专门准备虚拟机环境了,直接在macOS上安装测试下其基础功能。1.使用Homebrew安装MongoDB2.启动/停止MongoDB服务3.启动......
  • Rockchip RK3588 - Rockchip Linux SDK脚本分析
    ----------------------------------------------------------------------------------------------------------------------------开发板:ArmSoM-Sige7开发板eMMC:64GBLPDDR4:8GB显示屏:15.6英寸HDMI接口显示屏u-boot:2017.09linux:5.10-------------------------------......
  • Linux C++ 045-设计模式之工厂模式
    LinuxC++045-设计模式之工厂模式本节关键字:Linux、C++、设计模式、简单工厂模式、工厂方法模式、抽象工厂模式相关库函数:简单工厂模式基本简介从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactoryMethod)模式,但不属于23种GOF设计模......
  • 2024年06月CCF-GESP编程能力等级认证Python编程三级真题解析
    本文收录于专栏《Python等级认证CCF-GESP真题解析》,专栏总目录:点这里,订阅后可阅读专栏内所有文章。一、单选题(每题2分,共30分)第1题小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证考试的第1级,那他可以选择的认证语言有几种?()A.1B.2C.3D.4答案:C第......
  • Nuxt框架中内置组件详解及使用指南(四)
    title:Nuxt框架中内置组件详解及使用指南(四)date:2024/7/9updated:2024/7/9author:cmdragonexcerpt:摘要:本文详细介绍了Nuxt3框架中的两个内置组件:和的使用方法与示例。用于捕获并处理客户端错误,提供了错误处理和自定义错误展示的功能;而是一个实验性组件,用于渲染无客......
  • 全面解析Python:现代编程语言
    引言Python是一种高级、解释型、动态和面向对象的编程语言,由GuidovanRossum于1991年发布。它以简洁、可读性强的代码和丰富的库支持著称,是数据科学、机器学习、Web开发、自动化脚本等领域的首选语言。本文将详细介绍Python的基本概念、高级主题、数据结构、文件操作、模块和......
  • Linux常用命令
    1.1ls语法:ls[选项][⽬录或⽂件]功能:对于⽬录,该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件,将列出⽂件名以及其他信息。-a列出⽬录下的所有⽂件,包括以.开头的隐含⽂件。-d将⽬录象⽂件⼀样显⽰,⽽不是显⽰其下的⽂件。如:ls‒d指定⽬录-k以k字节的形式表......