[Linux operating system] Example to explain the commonly used functions of file io in Linux system programming

In Linux system programming, file IO operation is one of the very common and important operations. Through file IO operations, we can open, read, write, and close files, and perform operations such as locating, copying, deleting, and renaming files. This blog will introduce some commonly used file IO operation functions.
insert image description here

1. open()

1.1 Prototype, parameter and return value description

1.1.1 Prototype:

The open() function is one of the commonly used file IO operation functions in Linux system programming. It is used to open a file and return a file descriptor for subsequent file read and write operations.
The prototype of the open() function is as follows:

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

int open(const char *pathname, int flags, mode_t mode);

1.1.2 Parameter description:

  1. pathname: The path name of the file to open.
  2. flags: The mode flag for opening the file, which can be a combination of the following modes:
    • O_RDONLY: Open the file in read-only mode.
    • O_WRONLY: Open the file in write-only mode.
    • O_RDWR: Open the file in read-write mode.
    • O_CREAT: Creates the file if it does not exist.
    • O_EXCL: Used with O_CREAT, if the file already exists, an error is returned.
    • O_TRUNC: If the file exists and is opened in writable mode, truncate the file to 0.
    • O_APPEND: Append data at the end of the file.
  3. mode: The access right when creating a file, only valid when using O_CREAT.
    You can use the following macros to set permissions:
    • S_IRUSR: User read permission.
    • S_IWUSR: User write permission.
    • S_IXUSR: User execute permission.
    • S_IRGRP: Group read permission.
    • S_IWGRP: Group write permission.
    • S_IXGRP: Group execute permission.
    • S_IROTH: Read permission for other users.
    • S_IWOTH: Write permissions for other users.
    • S_IXOTH: Execute permissions for other users.

1.1.3 Return value:

  • Success : Returns a non-negative integer file descriptor for subsequent file IO operations.
  • Failure : Returns -1 and sets the errno variable to indicate the type of error.

1.2 Function examples

Here is an example using the open() function:

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

int main() {
    
    
    int fd;

    // 打开文件
    fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (fd == -1) {
    
    
        perror("open");
        return errno;
    }

    // 写入数据
    char buffer[] = "Hello, world!";
    ssize_t ret = write(fd, buffer, sizeof(buffer) - 1);
    if (ret == -1) {
    
    
        perror("write");
        close(fd);
        return errno;
    }

    // 关闭文件
    close(fd);

    return 0;
}

1.3 Code Explanation

In the above example, we first open a file example.txt in write-only mode using the open() function. If the file does not exist, create the file and set the access permissions to be readable and writable by the user. If opening the file fails, we use the perror() function to print the error message and return the errno variable.

Next, we write data to the file using the write() function. In this example, we wrote the string "Hello, world!". If writing data fails, we also use the perror() function to print an error message and return the errno variable before closing the file.

Finally, we close the file using the close() function.

2. close()

2.1 Prototype, parameter and return value description

2.1.1 Prototype:

The close() function is a function used to close files in Linux system programming. It takes a file descriptor as an argument and returns an integer value indicating whether the operation was successful.

The prototype of the close() function is as follows:

#include <unistd.h>

int close(int fd);

2.1.2 Parameters:

  • fd: The file descriptor to close.

2.1.3 Return value:

  • Success : returns 0.
  • Failure : Returns -1 and setserrnoa variable to indicate the type of error.

2.2 Function examples

Here is an example using the close() function:

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

int main() {
    
    
    int fd;

    // 打开文件
    fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
    
    
        perror("open");
        return errno;
    }

    // 关闭文件
    int ret = close(fd);
    if (ret == -1) {
    
    
        perror("close");
        return errno;
    }

    return 0;
}

2.3 Code explanation

In the above example, we first use open()the function to open a file in read-only mode example.txtand store the returned file descriptor in a variable fd. If opening the file fails, we use perror()a function to print an error message and return errnoa variable.

Next, we use close()the function to close the file. If closing the file fails, we also use perror()the function to print an error message and return errnoa variable.

It should be noted that after closing the file, we should not perform any operations on the file descriptor.

3. read()

3.1 Prototype, parameter and return value description

3.1.1 Prototype:

The read() function is a function used in Linux system programming to read data from a file. It takes a file descriptor, a buffer address, and a maximum number of bytes to read as parameters, and returns the actual number of bytes read.

The prototype of the read() function is as follows:

#include <unistd.h>

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

3.1.2 Parameters:

  • fd: The file descriptor of the file to read.
  • buf: The address of the buffer used to store the read data.
  • count: The maximum number of bytes to read.

3.1.3 Return value:

  • Success : Returns the number of bytes actually read.
  • Failure : Returns-1witherrnoa variable set to indicate the type of error.

3.2 Function examples

Here is an example using the read() function:

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

int main() {
    
    
    int fd;

    // 打开文件
    fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
    
    
        perror("open");
        return errno;
    }

    // 读取数据
    char buffer[100];
    ssize_t ret = read(fd, buffer, sizeof(buffer));
    if (ret == -1) {
    
    
        perror("read");
        close(fd);
        return errno;
    }

    // 输出读取的数据
    printf("Read %ld bytes: %s\n", ret, buffer);

    // 关闭文件
    close(fd);

    return 0;
}

3.3 Code Explanation

In the above example, we first use open()the function to open a file in read-only mode example.txtand store the returned file descriptor in a variable fd. If opening the file fails, we use perror()a function to print an error message and return errnoa variable.

Next, we use read()functions to read data from the file. We define a buffer of length 100 bufferand pass it as an argument to read()the function. read()The function will try to read countbytes of data and store them in the buffer. If reading the data fails, we also use perror()the function to print the error message and return the variable before closing the file errno.

Finally, we use printf()a function to output the read data and close()a function to close the file.

It should be noted that the read() function is a blocking function. If there is not enough data to read in the file, it will wait until there is enough data to read or an error occurs. If you need to read data non-blocking, you can use the fcntl() function to set the file descriptor to non-blocking mode.

4. write()

4.1 Prototype, parameter and return value description

4.1.1 Prototype:

The write() function is a function used to write data to a file in Linux system programming. It takes a file descriptor, a data buffer address, and the number of bytes to write as parameters, and returns the actual number of bytes written.

The prototype of the write() function is as follows:

#include <unistd.h>

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

4.1.2 Parameters:

  • fd: The file descriptor of the file to write to.
  • buf: The address of the buffer for the data to be written.
  • count: The number of bytes to write.

4.1.3 Return value:

  • Success : Returns the number of bytes actually written.
  • Failure : Returns-1witherrnoa variable set to indicate the type of error.

4.2 Function examples

Here is an example using the write() function:

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

int main() {
    
    
    int fd;

    // 打开文件
    fd = open("example.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd == -1) {
    
    
        perror("open");
        return errno;
    }

    // 写入数据
    char buffer[] = "Hello, World!";
    ssize_t ret = write(fd, buffer, sizeof(buffer) - 1);
    if (ret == -1) {
    
    
        perror("write");
        close(fd);
        return errno;
    }

    // 关闭文件
    close(fd);

    return 0;
}

4.3 Code Explanation

In the above example, we first use open()the function to open a file in write-only mode example.txtand store the returned file descriptor in a variable fd. If opening the file fails, we use perror()a function to print an error message and return errnoa variable.

Next, we use write()the function to write the data to the file. We define a string bufferand pass it as an argument to write()the function. write()The function will try to write countbytes of data to the file. If writing data fails, we also use perror()the function to print the error message and return the variable before closing the file errno.

Finally, we use close()the function to close the file.

It should be noted that the write() function is a blocking function, if the file cannot immediately accept written data (for example, insufficient disk space), it will wait until data can be written or an error occurs. If you need to write data non-blocking, you can use the fcntl() function to set the file descriptor to non-blocking mode.

5. lseek()

5.1 Prototype, parameter and return value description

5.1.1 Prototype:

The lseek() function is a function used in Linux system programming to locate the read and write positions in a file. It takes a file descriptor, an offset, and a starting position as parameters, and returns the new reading and writing position.

The prototype of the lseek() function is as follows:

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

5.1.2 Parameters:

  • fd: The file descriptor of the file to locate.
  • offset: Offset, which can be positive, negative or zero.
  • whence: The starting position, which can take the following three values:
    • SEEK_SET: Calculate the offset from the beginning of the file.
    • SEEK_CUR: Calculate the offset from the current read/write position.
    • SEEK_END: Calculate the offset from the end of the file.

5.1.3 Return value:

  • SUCCESS : Returns the new read and write position.
  • Failure : Returns-1witherrnoa variable set to indicate the type of error.

5.2 Function Example

Here is an example using the lseek() function:

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

int main() {
    
    
    int fd;

    // 打开文件
    fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
    
    
        perror("open");
        return errno;
    }

    // 定位读写位置
    off_t ret = lseek(fd, 5, SEEK_SET);
    if (ret == -1) {
    
    
        perror("lseek");
        close(fd);
        return errno;
    }

    // 读取数据
    char buffer[10];
    ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
    if (n == -1) {
    
    
        perror("read");
        close(fd);
        return errno;
    }
    buffer[n] = '\0';
    printf("Data: %s\n", buffer);

    // 关闭文件
    close(fd);

    return 0;
}

5.3 Code Explanation

In the above example, we first use open()the function to open a file in read-only mode example.txtand store the returned file descriptor in a variable fd. If opening the file fails, we use perror()a function to print an error message and return errnoa variable.

Next, we use lseek()the function to locate the read and write position to the 5th byte after the beginning of the file. We pass the file descriptor, offset and starting position as arguments to lseek()the function. If locating the read/write location fails, we also use perror()the function to print an error message and return errnothe variable before closing the file.

Then, we use read()functions to read data from the file. We define a buffer bufferand pass it as an argument to read()the function. read()The function will try to read countbytes of data into the buffer. If reading the data fails, we also use perror()the function to print the error message and return the variable before closing the file errno. Finally, we append a null character at the end of the buffer and use printf()the function to print the read data.

Finally, we use close()the function to close the file.

It should be noted that the lseek() function can be used to locate the reading and writing position, but it will not change the size of the file. If you need to change the size of the file, you can use the truncate() function or the ftruncate() function.

6. stat()

6.1 Prototype, parameter and return value description

6.1.1 Prototype:

The stat() function is a function used to obtain file information in Linux system programming. It takes a file path as an argument and returns a structure containing the file information.

The prototype of the stat() function is as follows:

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

int stat(const char *pathname, struct stat *buf);

6.1.2 Parameters:

  • pathname: The file path to get information from.
  • buf: A pointer to a structure used to store file information.

6.1.3 Return value:

  • Success : returns 0.
  • Failure : Returns-1witherrnoa variable set to indicate the type of error.

struct statThe structure contains various information about the file, including file type, permission, size, creation time, modification time, etc.

The following is the definition of the struct stat structure:

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;     // 文件系统的块大小
    blkcnt_t  st_blocks;      // 分配给文件的块数
    time_t    st_atime;       // 文件的最后访问时间
    time_t    st_mtime;       // 文件的最后修改时间
    time_t    st_ctime;       // 文件的最后状态改变时间
};

6.2 Function examples

Here is an example using the stat() function:

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

int main() {
    
    
    const char *pathname = "example.txt";
    struct stat file_info;

    // 获取文件信息
    int ret = stat(pathname, &file_info);
    if (ret == -1) {
    
    
        perror("stat");
        return errno;
    }

    // 打印文件信息
    printf("File Size: %ld bytes\n", file_info.st_size);
    printf("File Permissions: %o\n", file_info.st_mode & 0777);
    printf("File Owner UID: %d\n", file_info.st_uid);
    printf("File Owner GID: %d\n", file_info.st_gid);

    return 0;
}

6.3 Code Explanation

In the above example, we first define a file path pathnameand a struct statstructure file_infoto store the obtained file information.

Then, we use stat()functions to store the file information into file_infoa structure. We file_infopass the file path and structure pointer as parameters to stat()the function. If getting the file information fails, we use perror()a function to print the error message and return errnoa variable.

Finally, we use printf()the function to print the obtained file information, including file size, file permissions, UIDand the sum of the file owner GID, etc.

It should be noted that the stat() function can only obtain the information of the file, but cannot modify the information of the file. If you need to modify the information of the file, you can use the chmod() function to modify the permissions of the file.

7. fcntl()

7.1 Prototype, parameter and return value description

7.1.1 Prototype:

The fcntl() function is a function used to control and operate file descriptors in Linux system programming. It can be used to set file status flags, get file status flags, set file locks, etc.

The prototype of the fcntl() function is as follows:

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

7.1.2 Parameters:

  • fd: The file descriptor, which can be the file descriptor of the open file or the file descriptor of the socket.
  • cmd: Control command, used to specify the operation to be performed.
  • arg: Optional parameter, used to pass parameters for a specific operation.

7.1.3 Return value:

  • Success : Return different values ​​according to different operation commands, usually 0 or a positive integer.
  • Failure : Returns-1witherrnoa variable set to indicate the type of error.

The following are some commonly used commands of the fcntl() function:

  • F_DUPFD: Duplicate the file descriptor, creating a new file descriptor that points to the same open file as the original.
  • F_GETFD: Get the file status flags for a file descriptor.
  • F_SETFD: Set the file status flags for the file descriptor.
  • F_GETFL: Get the open mode and status flags of the file.
  • F_SETFL: Set the opening method and status flag of the file.
  • F_GETLK: Get file lock information.
  • F_SETLK: Set file lock.
  • F_SETLKW: Set the file lock, if the lock cannot be acquired, block and wait.

7.2 Function example

Here is an example using the fcntl() function:

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

int main() {
    
    
    int fd = open("example.txt", O_RDWR);
    if (fd == -1) {
    
    
        perror("open");
        return errno;
    }

    // 获取文件的打开方式和状态标志
    int flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
    
    
        perror("fcntl");
        return errno;
    }

    // 设置文件的状态标志为非阻塞
    flags |= O_NONBLOCK;
    int ret = fcntl(fd, F_SETFL, flags);
    if (ret == -1) {
    
    
        perror("fcntl");
        return errno;
    }

    // 关闭文件描述符
    close(fd);

    return 0;
}

7.3 Code Explanation

In the above example, we first open()open a file using the function and store the returned file descriptor in the variable fd. If opening the file fails, we use perror()a function to print an error message and return errnoa variable.

We then use fcntl()functions to get the file's open mode and status flags. Pass the file descriptor and F_GETFLcommand to fcntl()the function as parameters, and store the obtained file status flags in variables flags. If it fails to get the file status flag, we also use perror()the function to print the error message and return errnothe variable.

Next, we set the file's status flag to non-blocking by bitwise ORing O_NONBLOCKthe flag bits with flagsWe then use fcntl()a function to set the modified status flags back to the file descriptor. Pass the file descriptor, F_SETFLcommand, and modified status flags to the function as arguments fcntl(). If setting the file status flag fails, we also use perror()the function to print an error message and return errnoa variable.

Finally, we use close()the function to close the file descriptor, freeing the resource.

It should be noted that the use of the fcntl() function is very flexible, and various operations can be performed as needed, such as copying file descriptors, acquiring file locks, and so on. When using the fcntl() function, you need to pay attention to error handling and ensure the validity of the file descriptor. At the same time, the file descriptor needs to be closed in time when it is no longer needed to release resources and avoid resource leaks.

Summarize

File IO operations are an important part of Linux system programming. Through functions such as open(), close(), read(), write()etc., we can open, read and write files. With lseek()functions, we can navigate within a file. Through functions such as stat(), fcntl(), dup()and so on, we can obtain the status information of the file, perform control operations on the file descriptor, copy the file descriptor, and so on.

In addition to the above functions, there are many other functions that can be used for file IO operations, such as mkdir()for creating directories, rmdir()for deleting directories, unlink()for deleting files, rename()for renaming files, etc.

Guess you like

Origin blog.csdn.net/Goforyouqp/article/details/132211498
Recommended