文件IO之文件杂项操作

文件杂项操作

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错误)、
ENOENTold_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 fstatlstat 都返回 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值