ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux 系统文件读写相关函数说明

2022-01-04 18:03:34  阅读:134  来源: 互联网

标签:文件 函数 int 读写 系统文件 Linux 返回值 include open


前言:

  在 Linux 系统中必须要使用系统提供的 IO 函数才能基于这些文件描述符完成对相关文件的读写操作。

文件相关函数说明:

open/close:

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

/*
open是一个系统函数, 只能在linux系统中使用, windows不支持
fopen 是标准c库函数, 一般都可以跨平台使用, 可以这样理解:
		- 在linux中 fopen底层封装了Linux的系统API open
		- 在window中, fopen底层封装的是 window 的 api
*/
// 打开一个已经存在的磁盘文件
int open(const char *pathname, int flags);
// 打开磁盘文件, 如果文件不存在, 就会自动创建
int open(const char *pathname, int flags, mode_t mode);

**参数介绍:**

pathname: 被打开的文件的文件名

flags: 使用什么方式打开指定的文件,这个参数对应一些宏值,需要根据实际需求指定

必须要指定的属性 , 以下三个属性不能同时使用,只能任选其一
O_RDONLY: 以只读方式打开文件
O_WRONLY: 以只写方式打开文件
O_RDWR: 以读写方式打开文件
可选属性 , 和上边的属性一起使用
O_APPEND: 新数据追加到文件尾部,不会覆盖文件的原来内容
O_CREAT: 如果文件不存在,创建该文件,如果文件存在什么也不做
O_EXCL: 检测文件是否存在,必须要和 O_CREAT 一起使用,不能单独使用: O_CREAT | O_EXCL
检测到文件不存在,创建新文件
检测到文件已经存在,创建失败,函数直接返回 - 1(如果不添加这个属性,不会返回 - 1)
mode: 在创建新文件的时候才需要指定这个参数的值,用于指定新文件的权限,这是一个八进制的整数

这个参数的最大值为:0777

**返回值:**

成功:返回内核分配的文件描述符,这个值被记录在内核的文件描述符表中,这是一个大于 0 的整数
失败: -1

#include <unistd.h>
int close(int fd);

read/write

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
fd: 文件描述符,open () 函数的返回值,通过这个参数定位打开的磁盘文件
buf: 是一个传出参数,指向一块有效的内存,用于存储从文件中读出的数据
传出参数:类似于返回值,将变量地址传递给函数,函数调用完毕,地址中就有数据了
count: buf 指针指向的内存的大小,指定可以存储的最大字节数
返回值:
大于 0: 从文件中读出的字节数,读文件成功
等于 0: 代表文件读完了,读文件成功
-1: 读文件失败了

write 函数用于将数据写入到文件内部,在通过 open 打开文件的时候需要指定写权限,函数原型如下:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
fd: 文件描述符,open () 函数的返回值,通过这个参数定位打开的磁盘文件
buf: 指向一块有效的内存地址,里边有要写入到磁盘文件中的数据
count: 要往磁盘文件中写入的字节数,一般情况下就是 buf 字符串的长度,strlen (buf)
返回值:
大于 0: 成功写入到磁盘文件中的字节数
-1: 写文件失败了

上述函数使用

// 文件的拷贝
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main()
{
    // 1. 打开存在的文件open.txt, 读这个文件,注意文件的路径
    int fd1 = open("./open.txt", O_RDONLY);
    if(fd1 == -1)
    {
        perror("open-readfile");
        return -1;
    }
    // 2. 打开不存在的文件, 将其创建出来, 将从open.txt读出的内容写入这个文件中
    int fd2 = open("bak.txt", O_WRONLY|O_CREAT, 0664);
    if(fd2 == -1)
    {
        perror("open-writefile");
        return -1;
    }
    // 3. 循环读文件, 循环写文件
    char buf[1024];
    int len = -1;
    while( (len = read(fd1, buf, sizeof(buf))) > 0 )
    {
        // 将读到的数据写入到另一个文件中
        write(fd2, buf, len); 
    }
    // 4. 关闭文件
    close(fd1);
    close(fd2);

    return 0;
}

lseek
函数原型如下:

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

off_t lseek(int fd, off_t offset, int whence);
参数:
fd: 文件描述符,open () 函数的返回值,通过这个参数定位打开的磁盘文件
offset: 偏移量,需要和第三个参数配合使用
whence: 通过这个参数指定函数实现什么样的功能
SEEK_SET: 从文件头部开始偏移 offset 个字节
SEEK_CUR: 从当前文件指针的位置向后偏移 offset 个字节
SEEK_END: 从文件尾部向后偏移 offset 个字节
返回值:
成功:文件指针从头部开始计算总的偏移量
失败: -1

**常用文件指针移动函数:**
**文件指针移动到文件头部:**
lseek(fd, 0, SEEK_SET);
**得到当前文件指针的位置:**
lseek(fd, 0, SEEK_CUR); 
**得到文件总大小:**
lseek(fd, 0, SEEK_END);

truncate/ftruncate

函数原型说明如下:

// 拓展文件或截断文件
#include <unistd.h>
#include <sys/types.h>

int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
参数:
path: 要拓展 / 截断的文件的文件名
fd: 文件描述符,open () 得到的
length: 文件的最终大小
文件原来 size > length,文件被截断,尾部多余的部分被删除,文件最终长度为 length
文件原来 size < length,文件被拓展,文件最终长度为 length
返回值:成功返回 0; 失败返回值 - 1

stat/lstat 函数

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

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

参数:
pathname: 文件名,要获取这个文件的属性信息
buf: 传出参数,文件的信息被写入到了这块内存中
返回值:函数调用成功返回 0,调用失败返回 -1
这个函数的第二个参数是一个结构体类型,这个结构体相对复杂,通过这个结构体可以存储得到的文件的所有属性信息,结构体原型如下:
struct stat {
    dev_t          st_dev;        	// 文件的设备编号
    ino_t           st_ino;        	// inode节点
    mode_t      st_mode;      		// 文件的类型和存取的权限, 16位整形数  -> 常用
    nlink_t        st_nlink;     	// 连到该文件的硬连接数目,刚建立的文件值为1
    uid_t           st_uid;       	// 用户ID
    gid_t           st_gid;       	// 组ID
    dev_t          st_rdev;      	// (设备类型)若此文件为设备文件,则为其设备编号
    off_t            st_size;      	// 文件字节数(文件大小)   --> 常用
    blksize_t     st_blksize;   	// 块大小(文件系统的I/O 缓冲区大小)
    blkcnt_t      st_blocks;    	// block的块数
    time_t         st_atime;     	// 最后一次访问时间
    time_t         st_mtime;     	// 最后一次修改时间(文件内容)
    time_t         st_ctime;     	// 最后一次改变时间(指属性)
};
获取文件属性实例:
#include <sys/stat.h>

int main()
{
    // 1. 定义结构体, 存储文件信息
    struct stat myst;
    // 2. 获取文件属性 open.txt
    int ret = stat("./open.txt", &myst);
    if(ret == -1)
    {
        perror("stat");
        return -1;
    }
    printf("文件大小: %d\n", (int)myst.st_size);
    return 0;
}

opendir/readdir/closedir 函数

#include <sys/types.h>
#include <dirent.h>
// 打开目录
DIR *opendir(const char *name);
参数: name -> 要打开的目录的名字
返回值: DIR*, 结构体类型指针。打开成功返回目录的实例,打开失败返回 NULL

目录打开之后,就可以通过 readdir () 函数遍历目录中的文件信息了。每调用一次这个函数就可以得到目录中的一个文件信息,当目录中的文件信息被全部遍历完毕会得到一个空对象。先来看一下这个函数原型:
// 读目录
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数:dirp -> opendir () 函数的返回值
返回值:函数调用成功,返回读到的文件的信息,目录文件被读完了或者函数调用失败返回 NULL
函数返回值 struct dirent 结构体原型如下:

struct dirent {
    ino_t          d_ino;       /* 文件对应的inode编号, 定位文件存储在磁盘的那个数据块上 */
    off_t          d_off;       /* 文件在当前目录中的偏移量 */
    unsigned short d_reclen;    /* 文件名字的实际长度 */
    unsigned char  d_type;      /* 文件的类型, linux中有7中文件类型 */
    char           d_name[256]; /* 文件的名字 */
};
关于结构体中的文件类型 d_type,可使用的宏值如下:

DT_BLK:块设备文件
DT_CHR:字符设备文件
DT_DIR:目录文件
DT_FIFO :管道文件
DT_LNK:软连接文件
DT_REG :普通文件
DT_SOCK:本地套接字文件
DT_UNKNOWN:无法识别的文件类型
那么,如何通过 readdir () 函数遍历某一个目录中的文件呢?

// 打开目录
DIR* dir = opendir("/home/test");
struct dirent* ptr = NULL;
// 遍历目录
while( (ptr=readdir(dir)) != NULL)
{
    .......
}

目录操作完毕之后,需要通过 closedir() 关闭通过 opendir() 得到的实例,释放资源。函数原型如下:
// 关闭目录, 参数是 opendir() 的返回值
int closedir(DIR *dirp);
参数:dirp-> opendir () 函数的返回值
返回值:目录关闭成功返回 0, 失败返回 -1

目录函数实例说明–遍历目录:

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

int getMp3Num(const char* path)
{
    // 1. 打开目录
    DIR* dir = opendir(path);
    if(dir == NULL)
    {
        perror("opendir");
        return 0;
    }
    // 2. 遍历当前目录
    struct dirent* ptr = NULL;
    int count = 0;
    while((ptr = readdir(dir)) != NULL)
    {
        // 如果是目录 . .. 跳过不处理
        if(strcmp(ptr->d_name, ".")==0 ||
           strcmp(ptr->d_name, "..") == 0)
        {
            continue;
        }
        // 假设读到的当前文件是目录
        if(ptr->d_type == DT_DIR)
        {
            // 目录
            char newPath[1024];
            sprintf(newPath, "%s/%s", path, ptr->d_name);
            // 读当前目录的子目录
            count += getMp3Num(newPath);
        }
        else if(ptr->d_type == DT_REG)
        {
            // 普通文件
            char* p = strstr(ptr->d_name, ".mp3");
            // 判断文件后缀是不是 .mp3
            if(p != NULL && *(p+4) == '\0')
            {
                count++;
                printf("%s/%s\n", path, ptr->d_name);
            }
        }
    }

    closedir(dir);
    return count;
}

int main(int argc, char* argv[])
{
    // ./a.out path
    if(argc < 2)
    {
        printf("./a.out path\n");
        return 0;
    }

    int num = getMp3Num(argv[1]);
    printf("%s 目录中mp3文件个数: %d\n", argv[1], num);

    return 0;
}

到处就完成了基本函数的说明。

标签:文件,函数,int,读写,系统文件,Linux,返回值,include,open
来源: https://blog.csdn.net/houxian1103/article/details/122306661

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有