Linux C编程基础知识(文件目录操作)
1.标准C库API(文件流操作,跨平台)
1.1.fopen:文件打开
- 函数原型:
FlLE *fopen(const char *pathname,const char mode);
- 功能:打开指定路径的文件,返回文件流指针(FILE),打开失败返回NULL并设置ermno。
- 参数:
- pathname文件路径(相对路径如"./test.txt",绝对路径如"home/test/test.txt")。
- mode:
- "r":只读模式,文件必须存在无法写入,文件不存在则失败
- "w":只写模式,文件不存在则创建,存在则清空内容覆盖原有数据,慎用
- "a":追加模式,文件不存在则创建,写入内容追加到文件未尾不覆盖原有数据,适合日志写入
- "r+":读写模式,文件必须存在可同时读写,不创建新文件
- "w+":读写模式,文件不存在则创建,存在则清空覆盖原有数据,可读写
- "a+":读写模式,文件不存在则创建,写入追加到末尾读操作可从头开始,写操作仅追加
- "rb""wb":二进制只读/只写,处理二进制文件(如图片、可执行程序),避免换行符转换
- 返回值:成功返回非NULL的FILE指针,失败返回NULL并设置ermno(可通过perror()打印错误信息)
1.2.fclose:文件关闭
- 函数原型:
int fclose(FILE*stream);
- 功能:关闭文件流,释放缓冲区资源,返回0表示成功,非0表示失败。
- 返回值:成功返回0,失败返回EOF(-1)并设置errno。
- 注意:
- 文件打开后必须关闭,否则会导致资源泄露、缓冲区数据丢失。
- 关闭后stream指针失效,不可再用于后续文件操作,建议手动置为NULL。
- 关闭失败通常是缓冲区同步失败(如磁盘满),需捕获错误。
1.3.fread:读取文件
- 函数原型:
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
- 功能:从文件流stream中读取数据,存入ptr指向的缓冲区。
- 参数说明:
- ptr:接收数据的缓冲区指针。
- size:每个数据块的字节大小。
- nmemb:要读取的最大数据块数量。
- stream:目标文件流指针。
- 返回值:实际成功读取的数据块数量(不是字节数)
- 返回值=nmemb:读取成功(已读取指定数量的数据块)。
- 返回值
- 返回值=0:无数据可读(文件末尾或读取失败)。
1.4.fwrite:写入文件
- 函数原型:
size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
- 功能:将ptr缓冲区中的数据写入文件流stream。
- 参数说明:与fread一致(ptr为待写入数据的缓冲区指针)。
- 返回值:实际成功写入的数据块数量,等于nmemb表示写入成功,小于nmemb表示写入失败。
1.5.fprintf:格式化写入
- 函数原型:
int fprintf(FILE *stream,const char *format,...);
- 功能:将格式化数据写入文件流stream(而非终端),支持%d、%s、%f等格式符。
1.6.fscanf:格式化读取
- 函数原型:
int fscanf(FILE *stream,const char *format,...);
- 功能:从文件流stream中按格式读取数据,存入指定变量。
1.7.fseek:设置文件指针位置
- 函数原型:
int fseek(FILE *stream,long offset,int whence);
- 功能:移动文件流stream的读写指针到指定位置。
- 参数说明:
- offset:偏移量(字节数,可正可负,正表示向后移动,负表示向前移动)。
- whence:偏移基准点
- SEEK_SET:以文件开头为基准点。
- SEEK_CUR:以当前文件指针位置为基准点。
- SEEK_END:以文件末尾为基准点。
- 返回值:0表示成功,非0表示失败。
1.8.ftell:获取当前文件指针位置
- 函数原型:
long ftell(FILE *stream);
- 功能:获取文件流stream当前读写指针距离文件开头的字节数。
- 返回值:当前文件指针距离文件开头的字节数,失败返回-1。
1.9.rewind:将文件指针重置到文件开头
- 函数原型:
void rewind(FlLE *stream);
- 功能:等价于fseek(stream,0,SEEK_SET),将读写指针重置到文件开头,无返回值。
2.Linux系统调用API(文件描述符操作,底层高效)
2.1.open:文件打开
- 函数原型:
int open(const char *pathname,int flags);int open(const char *pathname,int flags,mode_t mode);
- 功能:打开/创建文件,返回文件描述符(非负整数,失败返回-1并设置ermno)。
- 参数
- flags:打开标志(必选,可通过|组合多个标志)
- 基础标志(互斥,只能选一个)
- O_RDONLY:只读模式。
- O_WRONLY:只写模式。
- O_RDWR:读写模式。
- 附加标志(可选)
- O_CREAT:文件不存在则创建,必须配合mode参数设置文件权限。
- O_TRUNC:文件存在则清空内容(对应fopen的"w"模式)。
- O_APPEND:追加模式(对应fopen的"a"模式)。
- O_NONBLOCK:非阻塞模式(读写不阻塞,适合异步操作)。
- 基础标志(互斥,只能选一个)
- mode:文件权限(仅当O_CREAT时有效),用8进制数表示(如0644、0755)
- 0644:所有者可读可写(6=4+2),所属组/其他用户只读(4)。
- 0755:所有者可读可写可执行(7=4+2+1),所属组/其他用户可读可执行(5=4+1)。
- flags:打开标志(必选,可通过|组合多个标志)
- 返回值:成功返回非负整数(文件描述符,通常从 3开始,0/1/2分别为标准输入/输出/错误),失败返回-1并设置ermo。
2.2.close:文件关闭
- 函数原型:
int close(int fd);
- 功能:关闭文件描述符,释放文件资源,返回0表示成功,-1表示失败。
- 返回值:成功返回0,失败返回-1并设置errno。
- 注意:
- 文件描述符是有限资源(默认上限1024),打开后必须关闭,避免资源泄露。
- 关闭后fd失效,不可再用于后续文件操作,建议手动置为-1。
2.3.read:读取文件
- 函数原型:
ssize_t read(int fd,void *buf,size_t count);
- 功能:从文件描述符fd中读取最多count字节数据,存入buf缓冲区。
- 返回值:实际读取的字节数(0表示读取到文件末尾,-1表示出错)。
2.4.write:写入文件
- 函数原型:
ssize_t write(int fd,const void *buf,size_t count);
- 功能:将buf缓冲区中最多count字节数据写入文件描述符fd。
- 返回值:实际写入的字节数(-1表示出错)。
2.5.Iseek:文件指针定位
- 函数原型:
off_t lseek(int fd,off_t offset,int whence);
- 功能:与fseek类似,移动文件描述符fd的读写指针,实现随机读写。
- 参数:与fseek一致(whence同样支持SEEK_SET/SEEK_CUR/SEEK_END)。
- 返回值:移动后指针距离文件开头的字节数,失败返回-1。
2.6.chmod:文件权限修改
- 函数原型:
int chmod(const char *pathname,mode_t mode);
- 功能:修改文件/目录的权限,mode为8进制数(如0755)。
3.目录操作API(Linux特有,为主)
3.1.创建目录:mkdir
- 函数原型:
int mkdir(const char *pathname,mode_t mode);
- 功能:用于创建单个目录(不支持递归创建多级目录),对应Linux终端命令mkdir。
- 参数:
- pathname:待创建目录的路径(相对路径如"./test_dir",绝对路径如"home/test/test_dir")
- mode:目录权限(8进制数表示,核心取值0755(默认)、0700),规则与普通文件一致
- 返回值:成功返回0;失败返回-1并设置ermo(常见错误:EExIST目录已存在、EACCES权限不足、ENOENT上级目录不存在)。
- 注意:mkdir不支持递归创建(如"./a/b/c",若a目录不存在则创建失败),需手动逐级创建或调用第三方工具函数。
3.2.删除目录:rmdir
- 函数原型:
int rmdir(const char *pathname);
- 功能:用于删除空目录(非空目录删除失败),对应Linux终端命令rmdir。
- 参数:
- pathname:待删除目录的路径(相对/绝对路径)。
- 返回值:成功返回0;失败返回-1并设置 ero(常错误:ENOTEMPTY目录非空、EACCES权限不足、ENOENT目录不存在)
- 注意:若需删除非空目录,需先遍历目录删除所有文件/子目录,再调用rmdir删除空目录。
3.3.打开目录:opendir
- 函数原型:
DIR *opendir(const char *name);
- 功能:打开指定目录,返回目录流指针DIR参数name为目标目录的路径(相对/绝对路径)。
- 返回值:成功返回非NULL的DIR目录流指针;失败返回 NULL并设置 ermo(常见错误:ENOENT目录不存在、EACCES权限不足)。
3.4.读取目录项:readdir
- 函数原型:
struct dirent readdir(DIRdirp);
- 功能:循环读取目录流中的单个目录项,每次调用返回下一个目录项的信息,直到目录末尾。
- 参数:
- dirp:opendir返回的目录流指针。
- 目录项结构体:
struct dirent{ ino_t d_ino; //文件索引号 off_t d_off; //目录项偏移量 unsigned short d_reclen; //该目录项大小 unsigned char d_type; //文件类型 char d_name[256]; //文件名 };- 返回值:成功返回指向 studt drent的指针(当前日录项信息);目录末尾/失败:返回 NULL(日录末尾时emo不变;失败时 ero被设置,可通过perror排查)。
3.5.关闭目录:closedir
- 函数原型:
int closedir(DIR *dirp);
- 功能:关闭目录流,释放目录资源,对应opendir的反向操作。
- 参数:dirp为opendir返回的目录流指针。
- 返回值:成功返回0;失败返回-1并设置errno。
3.6.切换目录:chdir
- 函数原型:
int chdir(const char *pathname);
- 功能:切换进程的当前工作目录(对应Linux终端命令cd),进程后续的相对路径操作均基于新的工作目录。
- 参数:
- pathname:目标工作目录的路径(相对/绝对路径,必须是存在的目录)。
- 返回值:成功返回0;失败返回-1并设置 ero(常见错误:ENOENT目录不存在、EACCES权限不足、ENOTDIR路径不是目录)
- 注意:chdlir仅影响当前进程的工作目录,不影响调用该进程的终端(父进程)工作目录。
3.7.获取当前工作目录:getcwd
- 函数原型:
char *getcwd(char *buf,size_t size);
- 功能:获取进程当前的工作目录路径(对应Linux终端命令pvd),存入用户提供的缓冲区。
- 参数:
- buf:接收工作目录路径的缓冲区指针(需提前分配内存,可使用栈缓冲区或堆缓冲区)。
- size:缓冲区的字节大小(需足够容纳路径字符串+\0结束符)。
- 返回值:成功返回 buf指针(与传入的缓冲区指针一致),缓冲区中存储以IO结尾的工作目录路径;失败返回NULL并设置 emo(常见错误:ERANGE缓冲区过小、EACCES权限不足)。
4.文件属性
4.1.获取文件信息
函数原型:
int stat(const char *path,struct stat *buf)int fstat(int fd,struct stat *buf)int lstat(const char *path,struct stat *buf)
参数说明:
- path:文件路径
- fd:文件描述符
- buf:属性结构体
返回值:
- 成功:0
- 失败:NULL
属性结构体如下所示:
struct stat { dev_t st_dev; // 普通文件所在存储器的设备号 mode_t st_mode; // 文件类型、文件权限 ino_t st_ino; // 文件索引号 nlink_t st_nlink; // 引用计数 uid_t st_uid; // 文件所有者的UID gid_t st_gid; // 文件所属组的GID dev_t st_rdev; // 特殊文件的设备号 off_t st_size; // 文件大小 blkcnt_t st_blocks; // 文件所占数据块数目 time_t st_atime; // 最近访问时间 time_t st_mtime; // 最近修改时间 time_t st_ctime; // 最近属性更改时间 blksize_t st_blksize; // 写数据块建议值 };该结构体中有很多成员的含义和作用是一目了然的,比如:
- 文件索引号:st_ino,实质上是一个无符号整形数据,用来唯一确定分区中的文件。
- 引用计数:st_nlink,记录该文件的名字(或叫硬链接)总数,文件的别名可以用命令link或者函数link()来创建。当一个文件的引用计数st_ nlink为零时,系统将会释放清空该文件锁占用的一切系统资源。
- 文件所有者UID和所属组GID。
- 文件的大小。这个属性对只对普通文件有效。
- 文件所占数据块数目st_ blocks,表明该文件实际占用存储器空间。一个数据块一般为512字节。
- st_atime、st_mtime和st_ctime都是一个文件的时间戳,st_atime代表文件被访问了但是没有被修改的最近时间,st_mtime代表文件内容被修改的最近时间,st_ctime则代表了文件属性更改的最近时间。文件的时间戳对于某些场合来讲是至关重要的属性,比如工程管理器make,他的工作原理就完全基于文件的时间戳上,判断文件的被修改时间,决定其是否参与编译。
- st_blksize 是所谓的“写数据块”的建议值,因为当应用程序频繁地往存储器写入小块数据的时候,可能会导致效率的低下。
4.2.分离主次设备号
函数原型:
int major(dev_t dev) int minor(dev_t dev)
参数说明:
- dev:文件的设备号属性,来自stat结构体中的st_dev或者st_rdev
返回值:
- 成功:major返回主设备号,minor返回次设备号
- 失败:无
4.3.文件类型和权限
属性成员中的st_ mode 里面包含了文件类型和权限,st_ mode 实质上是-一个无符号16位短整型数,各个位域所包含的含义如下:
- st_mode[0:8]:对应地代表了文件的各个用户的权限。
- st_ mode[9]:存储了所谓的黏住位(只对目录有效),在拥有该目录的写权限的情况下,如果这一位被设置为1,那么某一用户也只能删除在本目录下属于自己的文件,否则可以删除任意文件。
- st_ mode[10]和st_ mode[11] 分别用来设置文件的suid(只对普通文件有效)和sgid(只对目录有效)。如果suid被设置为1,则任何用户在执行该文件的时候均会获得该文件所有者的临时授权,即其有效UID将等于文件所有者的UID。如果sgid被设置为1,则任何在该目录下执行的程序均会获得该目录所属组成员的临时授权,即其有效GID将等于该目录的所属组成员的GID。
- st_ mode[12:15]:用以标识Linux下不同的文件类型,由于Linux总共只有7种文件类型,因此4位足以表达。
下面的表格是st_ mode 的详细信息:
4.4.判断文件类型的宏
4.5.判断文件是否存在
函数原型:
int access(const char *filename, int mode);
参数定义:
- filename:可以填写文件夹路径或者文件路径
- mode:
- 0 (F_OK) 只判断是否存在
- 2 (R_OK) 判断写入权限
- 4 (W_OK) 判断读取权限
- 6 (X_OK) 判断执行权限
用于判断文件夹是否存在的时候,mode取0,判断文件是否存在的时候,mode可以取0、2、4、6。
返回值:
- 成功:若存在或者具有权限,返回值为0
- 失败:不存在或者无权限,返回值为-1
