Linux文件操作是系统编程中的核心内容,掌握相关函数能够高效管理文件与目录数据,这些函数遵循POSIX标准,通过文件描述符(非负整数)标识打开的文件,提供了从基础打开关闭到复杂属性修改的完整操作体系。
基础文件操作:打开与关闭
文件操作的第一步是获取文件描述符,open()函数承担这一核心功能,其原型为int open(const char *pathname, int flags, mode_t mode),其中pathname为文件路径,flags控制打开方式(如O_RDONLY只读、O_WRONLY只写、O_RDWR读写,O_CREAT创建文件、O_EXCL独占创建),mode指定新文件的权限(如0644表示所有者读写,其他用户只读),若成功,返回文件描述符;失败则返回-1并设置errno。
关闭文件描述符需使用close(),原型为int close(int fd),释放文件描述符后,系统将不再关联该描述符与文件,确保后续操作不会误用,需注意,进程终止时会自动关闭所有打开的文件描述符,但显式关闭是良好的编程习惯,可及时释放系统资源。
核心读写操作:数据传输 通过read()函数实现,原型为ssize_t read(int fd, void *buf, size_t count),从文件描述符fd读取最多count字节到缓冲区buf,返回实际读取的字节数(遇文件结束返回0,出错返回-1),读取文本文件时需循环调用read(),直到返回0表示读取完毕。
写入数据则使用write(),原型为ssize_t write(int fd, const void *buf, size_t count),将缓冲区buf中的count字节写入文件描述符fd,返回实际写入字节数(可能小于count,需处理部分写入情况),对于二进制文件,write()会精确写入指定字节数;对于文本文件,需注意换行符(\n)的转换(部分系统会自动将\r\n转为\n)。
文件指针控制通过lseek()实现,原型为off_t lseek(int fd, off_t offset, int whence)。whence指定偏移基准:SEEK_SET从文件头开始,SEEK_CUR从当前位置偏移,SEEK_END从文件末尾偏移。lseek(fd, 0, SEEK_SET)将指针移至文件头,lseek(fd, -10, SEEK_END)移至文件末尾前10字节。lseek()还可用于获取文件大小(lseek(fd, 0, SEEK_END)的返回值)。
文件属性与状态管理
获取文件属性需使用stat()系列函数,其中stat()通过文件名获取属性,原型为int stat(const char *pathname, struct stat *buf);fstat()通过文件描述符获取,原型为int fstat(int fd, struct stat *buf);lstat()与stat()类似,但不跟随符号链接(返回符号链接本身而非目标文件属性)。struct stat结构体包含关键信息:st_mode(文件类型与权限,通过宏S_ISREG()判断普通文件、S_ISDIR()判断目录)、st_size(文件字节数)、st_mtime(最后修改时间)、st_uid(所有者用户ID)等。
修改文件属性常用chmod()(权限)和chown()(所有者),原型分别为int chmod(const char *pathname, mode_t mode)和int chown(const char *pathname, uid_t owner, gid_t group),权限修改需注意umask(文件创建掩码)的影响,例如mode为0644时,实际权限为0644 & ~umask,检查文件访问权限可用access(),原型为int access(const char *pathname, int mode),mode取R_OK(读)、W_OK(写)、X_OK(执行)、F_OK(文件存在)。
目录操作与文件系统遍历
目录操作需结合opendir()、readdir()、closedir()函数。opendir()打开目录,返回DIR*结构体指针,原型为DIR *opendir(const char *name);readdir()读取目录项,原型为struct dirent *readdir(DIR *dirp),返回struct dirent结构体,其d_name成员存储文件名;closedir()关闭目录,原型为int closedir(DIR *dirp),遍历目录时,需循环调用readdir(),直至返回NULL(表示到达目录末尾或出错)。
创建目录使用mkdir(),原型为int mkdir(const char *pathname, mode_t mode),权限规则与open()的mode参数一致;删除空目录用rmdir(),原型为int rmdir(const char *pathname),获取当前工作目录则通过getcwd(),原型为char *getcwd(char *buf, size_t size),将当前目录路径存入buf,size需足够容纳路径长度(如NULL则动态分配内存)。
错误处理与资源管理
文件操作中,错误处理至关重要,系统通过errno全局变量记录错误码(如ENOENT文件不存在、EACCES权限不足),perror()函数可将错误码转换为可读字符串并输出到标准错误流,原型为void perror(const char *s)(输出格式为s: 错误信息)。strerror()函数可将错误码转为字符串,原型为char *strerror(int errnum),适合自定义错误提示。
资源管理方面,需确保打开的文件描述符、目录指针等及时释放,避免资源泄漏,在循环中打开文件后,应在循环内或循环结束后关闭文件描述符;使用opendir()打开目录后,必须调用closedir()关闭,原子性操作(如O_EXCL标志创建文件)可避免竞态条件,确保数据一致性。
Linux文件操作函数构成了系统与用户交互的桥梁,从基础的读写到复杂的属性管理,为应用程序提供了灵活的文件访问能力,理解这些函数的参数、返回值及错误处理机制,是编写健壮、高效系统程序的基础,实践中,需结合文件描述符管理、权限控制及资源释放等细节,确保程序的安全性与可靠性。