文件杂项操作
1 获取当前工作路径
- getcwd函数
getcwd 函数是用于获取当前工作目录的绝对路径的一个标准库函数
#include <unistd.h>
char *getcwd(char *buf, size_t size);
- 参数
buf
:这是一个指向字符数组的指针,用于存储当前工作目录的路径。如果这个参数是NULL
,getcwd
会分配一个足够大的缓冲区来存储路径,调用者需要负责在使用后释放这个缓冲区以避免内存泄漏。size
:这是缓冲区的大小,以字节为单位。它应该足够大以容纳当前工作目录的路径,包括终止的空字符(\0
)。
- 返回值
- 如果调用成功,
getcwd
返回指向buf
的指针(即传入的缓冲区地址),该缓冲区包含当前工作目录的路径。 - 如果调用失败,
getcwd
返回 NULL ,并设置全局变量errno
来指示错误类型。常见错误ERANGE
:如果 size 太小,无法存储当前工作目录的路径,getcwd
会设置errno
为 ERANGE`` 并返回NULL 。- 其他错误:可能包括权限问题(如当前目录或其父目录不可读)、内存分配失败等,这些都会导致
getcwd
返回 NULL 并设置相应的errno
值。
- 如果调用成功,
#include <iostream>
#include <unistd.h>
#include <limits.h>
using namespace std;
int main()
{
//limits.h定义了PATH_MAX,这是系统定义的一个常量,表示路径名的最大长度。
char cwd[PATH_MAX];
if(getcwd(cwd, PATH_MAX) != nullptr)
{
printf("Current working directory: %s\n", cwd);
}
else
{
perror("getcwd() error");
// 可以根据errno的值进一步处理错误
}
return 0;
}
#include <limits.h>
limits.h定义了PATH_MAX,这是系统定义的一个常量,表示路径名的最大长度。
2 更改当前工作路径
chdir
函数是 C 语言中用于改变当前工作目录的一个标准库函数。
#include <unistd.h>
int chdir(const char *path);
-
参数
path
: 一个指向以空字符结尾的字符串的指针,表示要切换到的目标目录的路径。这个路径可以是绝对路径,也可以是相对路径。如果是相对路径,则相对于当前工作目录进行解析。
-
返回值
-
成功时,
chdir
返回 0 。 -
失败时,
chdir
返回 -1 ,并设置全局变量errno
以指示错误的具体原因。常见错误码EACCES
: 权限被拒绝,表示进程对目标目录没有访问权限。ENOENT
: 路径中的某个组件不存在。ENOTDIR
: 路径中的某个组件不是目录。ELOOP
: 路径解析过程中遇到太多的符号链接(循环链接)。EINVAL
: 提供的路径指向一个目录,但该目录在当前的文件系统挂载点下不可访问(例如,因为权限问题)。
-
#include <iostream>
#include <unistd.h>
#include <limits.h>
using namespace std;
int main()
{
const char *new_dir= "/home/wanfeng/code/FIle_IO";
if(chdir(new_dir) == 0)
{
printf("现在的路径是: %s\n", new_dir);
}
//limits.h定义了PATH_MAX,这是系统定义的一个常量,表示路径名的最大长度。
char cwd[PATH_MAX];
if(getcwd(cwd, PATH_MAX) != nullptr)
{
printf("Current working directory: %s\n", cwd);
}
else
{
perror("getcwd() error");
// 可以根据errno的值进一步处理错误
}
return 0;
}
//结果是
//现在的路径是: /home/wanfeng/code/FIle_IO
//Current working directory: /home/wanfeng/code/FIle_IO
在 printf
中,%s
需要一个指向以 \0
结尾的字符串的指针作为参数,无论是字符数组还是 char*
类型都可以满足这个要求。
3 更改文件大小
truncate 函数在 Linux 系统上用于改变文件的大小。
如果文件的大小大于指定的新大小,则超出部分的内容会被丢弃。
如果文件的大小小于指定的新大小,并且文件是一个常规文件(不是设备文件、管道等),那么文件的长度会被扩展,新添加的部分会被填充为零字节。
#include <unistd.h>
#include <fcntl.h>
int truncate(const char *path, off_t length);
或者,对于打开的文件描述符:
#include <unistd.h>
int ftruncate(int fd, off_t length);
-
参数
-
path
: 指向要修改大小的文件的路径的指针(对于 truncate 函数)。 -
fd
: 打开文件的文件描述符(对于 ftruncate 函数)。 -
ength
: 要将文件大小设置为的新大小(以字节为单位)。
-
-
返回值
-
成功时, truncate 和 ftruncate 都返回 0 。
-
失败时,返回 -1 并设置全局变量 errno 以指示错误的具体原因。常见错误码
-
EACCES
: 权限被拒绝,表示进程对文件没有写权限。 -
EBADF
:fd
不是一个有效的文件描述符,或者该文件描述符没有引用一个打开的文件(对于ftruncate
)。 -
EINVAL
:length
是一个无效的文件大小(例如,负值)。 -
EISDIR
:path
引用的是一个目录,而truncate
不能用于目录。 -
ELOOP
: 在解析path
时遇到太多的符号链接。 -
ENAMETOOLONG
:path
的长度超过了文件系统允许的最大长度。 -
ENOENT
:path
中的某个组件不存在。 -
ENOTDIR
:path
中的某个组件不是目录,但在解析路径时是必需的。 -
EROFS
: 文件系统是只读的。 -
ETXTBSY
: 尝试修改一个正在执行的文本文件的大小。
-
-
示例
//File size truncated to 20 byte.#include <iostream>
#include <unistd.h>
#include <limits.h>
using namespace std;
int main()
{
const char* fielmath = "/home/wanfeng/code/test.txt";
off_t new_size = 20;
if(truncate(fielmath, new_size) == -1)
{
perror("truncate");
return 1;
}
printf("File size truncated to %lld byte.\n", (long long)new_size);
return 0;
}
//结果是
//File size truncated to 20 byte.
4 更改文件名字
在Linux系统中, rename 函数用于更改文件或目录的名称。
#include <stdio.h>
int rename(const char *old_filename, const char *new_filename);
-
参数
-
old_filename
: 指向要重命名的文件或目录的当前名称的指针。 -
new_filenam
: 指向文件或目录的新名称的指针。
-
-
返回值
成功时,rename 返回 0
。
失败时,返回 -1
并设置全局变量 errno
以指示错误的具体原因。常见的错误码包括
EACCES
(权限被拒绝)、
EBUSY (
设备或资源正忙,这通常不适用于文件重命名)、
EISDIR
( new_filename
是一个目录,但old_filename
不是)、
EINVAL
(无效的参数,如空指针)、
EIO
硬件I/O错误)、
ENOENT
( old_filename
不存在)、
ENOTDIR
(路径中的某个组件不是目录,但在解析路径时是必需的)、
EPERM
(操作不允许)、
EROFS
(文件系统是只读的)等。
注意
权限:调用进程必须对 old_filename
有写权限,并且如果 new_filename
所在的目录不同,则还必须有该目录的写权限和搜索权限(即执行权限,以便能够遍历到该目录)。
跨文件系统:在某些文件系统上,如果 old_filename
和 new_filename
位于不同的文件系统上,rename 可能会失败,并返回 EXDEV 错误。
目录:如果 old_filename
是一个目录,则 new_filename
也必须是一个目录,或者必须不存在(以便可以创建一个新目录)。重命名目录时,其内容(子文件和子目录)也会被移动。
错误处理:如果 rename
失败,应该检查 errno
以确定失败的原因。
#include <iostream>
#include <unistd.h>
#include <limits.h>
using namespace std;
int main()
{
const char *old_filename = "/home/wanfeng/code/test.txt";
const char *new_filename = "/home/wanfeng/code/test2.txt";;
if(rename(old_filename, new_filename) == -1)
{
perror("rename");
return 1;
}
printf("File renamed successfully.\n");
return 0;
}
//结果 File renamed successfully.
5 获取文件属性
在Linux系统中, stat
函数用于获取文件的状态信息,包括文件的大小、权限、所有者、组、最后访问 时间、最后修改时间等。
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
对于已经打开的文件描述符,可以使用fstat
函数:
#include <sys/stat.h>
#include <unistd.h>
int fstat(int fd, struct stat *buf);
另外,还有一个 lstat
函数,它类似于 stat
,但是当遇到符号链接时, lstat 返回的是链接本身的信 息,而不是链接指向的文件的信息:
#include <sys/stat.h>
int lstat(const char *pathname, struct stat *buf
另外,还有一个 lstat 函数,它类似于 stat ,但是当遇到符号链接时, lstat 返回的是链接本身的信 息,而不是链接指向的文件的信息:
#include <sys/stat.h>
int lstat(const char *pathname, struct stat *buf);
参数
-
pathname
: 指向要获取状态信息的文件的路径的指针(对于stat 和 lstat
函数)。 -
fd
: 打开文件的文件描述符(对于fstat
函数)。 -
buf
: 指向struct stat
结构的指针,该结构将用于存储文件的状态信息。 -
struct stat
结构包含了文件的各种状态信息。以下是一些重要的成员:-
st_dev
: 设备ID(文件系统所在的设备)。 -
st_ino
: 节点号(文件的唯一标识符)。 -
st_mode
: 文件类型和权限(例如,普通文件、目录、可执行文件等,以及读、写、执行权限)。 -
st_nlink
: 硬链接的数量。 -
st_uid
: 文件所有者的用户ID。 -
st_gid
: 文件所属组的组ID。 -
st_rdev
: 如果文件是设备文件,则这是设备ID。 -
st_size
: 文件的大小(以字节为单位)。 -
st_blksize
: 文件系统的I/O操作的最优块大小。 -
st_blocks
: 文件所占用的块数量(512字节为一个块)。 -
st_atime
: 最后访问时间(自Epoch以来的秒数)。 -
st_mtime
: 最后修改时间(自Epoch以来的秒数)。 -
st_ctime` : 最后状态改变时间(例如,权限或所有权改变,自Epoch以来的秒数)。
-
-
返回值
- 成功时,
stat
、fstat
和lstat
都返回 0 。 - 失败时,返回 -1 并设置全局变量
errno
以指示错误的具体原因。
- 成功时,
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
using namespace std;
int main()
{
const char *filepath = "/home/wanfeng/code/test1.txt";
struct stat fileStat;
if(stat(filepath, &fileStat) == -1)
{
perror("stat");
return 1;
}
printf("File size: %lld bytes\n" ,(long long)fileStat.st_size);
printf("Permissions: %o\n", fileStat.st_mode &0777);
printf("Last modified: %s", ctime(&fileStat.st_mtime));
return 0;
}
//结果
//File size: 0 bytes
//Permissions: 775
//Last modified: Mon May 5 15:14:05 2025
删除非空目录
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
// 递归删除目录及其内容的函数
void delete_directory_recursively(const char *dir_path)
{
struct dirent *entry;
char path[1024];
DIR *dp = opendir(dir_path);
if (dp == NULL)
{
perror("opendir");
return;
}
// 遍历目录中的每个条目
while ((entry = readdir(dp)))
{
// 跳过 "." 和 ".." 条目
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
// 构建条目的完整路径
snprintf(path, sizeof(path), "%s/%s", dir_path, entry->d_name);
// 检查条目是否是目录
struct stat statbuf;
if (lstat(path, &statbuf) == -1)
{
perror("lstat");
closedir(dp);
return;
}
if (S_ISDIR(statbuf.st_mode))
{
// 如果是目录,则递归删除
delete_directory_recursively(path);
}
else
{
// 如果是文件,则删除
if (remove(path) == -1)
{
perror("remove");
}
}
}
// 关闭目录流
closedir(dp);
// 最后删除空目录本身
if (rmdir(dir_path) == -1)
{
perror("rmdir");
}
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s <directory_path>\n", argv[0]);
exit(EXIT_FAILURE);
}
delete_directory_recursively(argv[1]);
return 0;
}
6 删除文件
- unlink函数
unlink
函数用于删除由 pathname
指定的文件。如果该文件是一个硬链接(在Linux中,文件和目录都是通过硬链接实现的,每个硬链接都有一个指向相同inode的目录项),则删除该链接。如果该文件是最后一个硬链接,并且没有进程打开该文件,则该文件的内容将被删除,并且相关的inode将被释放。
如果 pathname
是一个目录,则 unlink
函数将失败,并返回EPERM
错误(除非你是以超级用户身份运行,并且文件系统支持使用 unlink
删除目录,但这在大多数标准文件系统中是不允许的)。要删除目录,应该使用rmdir
函数。
#include <unistd.h>
int unlink(const char *pathname);参数
pathname : 指向要删除的文件或硬链接的路径名的指针。
- 参数
pathname
: 指向要删除的文件或硬链接的路径名的指针。
-
返回值
-
成功时,
unlink
返回0
。 -
失败时,返回
-1
并设置全局变量errno
以指示错误的具体原因。常见的错误码包括EACCES
(权限被拒绝)、-
ENOENT
(文件不存在)、 -
EISDIR
(路径是一个目录,但 unlink 不允许删除目录)、 -
ELOOP
(在解析路径名时遇到太多的符号链接)、 -
ENAMETOOLONG
(路径名太长)、 -
ENOTDIR
(路径中的某个组件不是目录,但在解析路径时是必需的)等。
-
-
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
using namespace std;
int main()
{
const char *filepath = "/home/wanfeng/code/test1.txt";
if(unlink(filepath) == -1)
{
perror("unlink");
return -1;
}
printf("文件删除成功");
return 0;
}
7.文件复制
Linux没有直接文件复制的函数,但是可以间接的方法
比如把test.txt-> test3.txt
1.打开test.txt (修改路径)创建test3.txt
2.读取test.txt写入test3.txt
3.关闭两个文件
示例
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
using namespace std;
int main()
{
// int open(const char *pathname, int flags, mode_t mode);
const char* filename = "/home/wanfeng/code/test.txt"; // 文件名
// 打开文件以写入。如果文件不存在,则创建它。
int fd = open(filename, O_RDWR | O_CREAT, 0777);
// 失败
if(fd == -1)
{
perror("打开文件失败");
return -1;
}
// 成功
cout << "文件打开成功" << endl;
//读取
char buffer[1024] = {0};
if(read(fd, buffer, sizeof(buffer) - 1) == -1)
{
perror("文件写入失败");
close(fd);// 读取失败后关闭文件
return -1;
}
// 输出读取到的内容
printf("Read from file: \n%s", buffer);
const char* filename1 = "/home/wanfeng/code/test3.txt";
int fd1 = open(filename1, O_RDWR | O_CREAT, 0777);
if(write(fd1, buffer, sizeof(buffer)- 1) == -1)
{
perror("文件写入失败");
return -1; // 写入失败后关闭文件
close(fd);
}
// 关闭文件(对于写入操作,这一步是可选的,但出于好习惯应关闭它)
close(fd);
close(fd1);
return 0;
}