getcwd系统调用及示例

getcwd – 获取当前工作目录

getcwd – 获取当前工作目录

函数介绍

getcwd系统调用用于获取进程当前的工作目录路径。它返回一个以null结尾的字符串,表示当前目录的绝对路径名。

函数原型

#include <unistd.h>

char *getcwd(char *buf, size_t size);

功能

获取进程当前工作目录的绝对路径名。

参数

  • char *buf: 指向存储路径名的缓冲区
  • size_t size: 缓冲区大小(字节)

返回值

  • 成功时返回指向缓冲区的指针(buf)
  • 失败时返回NULL,并设置errno:
    • EINVAL: size参数为0且buf非NULL
    • ERANGE: 缓冲区太小
    • ENOMEM: 内存不足

相似函数

  • chdir(): 改变当前工作目录
  • fchdir(): 通过文件描述符改变当前工作目录

示例代码

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <limits.h>

int main() {
    char buffer[PATH_MAX];
    char *result;
    
    printf("=== Getcwd函数示例 ===\n");
    
    // 示例1: 基本的获取当前目录操作
    printf("\n示例1: 基本的获取当前目录操作\n");
    
    // 方法1: 使用预分配的缓冲区
    result = getcwd(buffer, sizeof(buffer));
    if (result != NULL) {
        printf("当前工作目录: %s\n", buffer);
    } else {
        perror("获取当前目录失败");
    }
    
    // 方法2: 让系统分配内存(buf为NULL,size为0)
    char *dynamic_buffer = getcwd(NULL, 0);
    if (dynamic_buffer != NULL) {
        printf("动态分配的当前目录: %s\n", dynamic_buffer);
        free(dynamic_buffer);  // 需要手动释放内存
    } else {
        perror("动态获取当前目录失败");
    }
    
    // 示例2: 缓冲区大小处理
    printf("\n示例2: 缓冲区大小处理\n");
    
    // 测试不同大小的缓冲区
    size_t sizes[] = {10, 50, 100, PATH_MAX};
    for (int i = 0; i < 4; i++) {
        char small_buffer[1000];  // 足够大的缓冲区
        printf("尝试使用大小为 %zu 的缓冲区: ", sizes[i]);
        
        result = getcwd(small_buffer, sizes[i]);
        if (result != NULL) {
            printf("成功,目录长度: %zu 字节\n", strlen(small_buffer));
        } else {
            if (errno == ERANGE) {
                printf("失败 - 缓冲区太小\n");
            } else {
                printf("失败 - %s\n", strerror(errno));
            }
        }
    }
    
    // 示例3: 创建测试目录并切换
    printf("\n示例3: 目录切换演示\n");
    
    // 保存原始目录
    char original_dir[PATH_MAX];
    if (getcwd(original_dir, sizeof(original_dir)) == NULL) {
        perror("保存原始目录失败");
        exit(EXIT_FAILURE);
    }
    printf("原始目录: %s\n", original_dir);
    
    // 创建测试目录
    const char *test_dir = "test_getcwd_dir";
    if (mkdir(test_dir, 0755) == -1 && errno != EEXIST) {
        perror("创建测试目录失败");
    } else {
        printf("创建测试目录: %s\n", test_dir);
        
        // 切换到测试目录
        if (chdir(test_dir) == -1) {
            perror("切换目录失败");
        } else {
            printf("切换到测试目录\n");
            
            // 获取当前目录
            result = getcwd(buffer, sizeof(buffer));
            if (result != NULL) {
                printf("切换后当前目录: %s\n", buffer);
                
                // 验证是否正确切换
                if (strstr(buffer, test_dir) != NULL) {
                    printf("目录切换验证成功\n");
                }
            }
            
            // 在测试目录中创建子目录
            const char *sub_dir = "sub_directory";
            if (mkdir(sub_dir, 0755) == -1 && errno != EEXIST) {
                perror("创建子目录失败");
            } else {
                printf("创建子目录: %s\n", sub_dir);
                
                // 切换到子目录
                if (chdir(sub_dir) == -1) {
                    perror("切换到子目录失败");
                } else {
                    printf("切换到子目录\n");
                    
                    result = getcwd(buffer, sizeof(buffer));
                    if (result != NULL) {
                        printf("子目录路径: %s\n", buffer);
                    }
                }
            }
        }
        
        // 返回原始目录
        if (chdir(original_dir) == -1) {
            perror("返回原始目录失败");
        } else {
            printf("返回原始目录\n");
            result = getcwd(buffer, sizeof(buffer));
            if (result != NULL) {
                printf("确认当前目录: %s\n", buffer);
            }
        }
    }
    
    // 示例4: 错误处理演示
    printf("\n示例4: 错误处理演示\n");
    
    // 测试缓冲区太小的情况
    char tiny_buffer[5];
    result = getcwd(tiny_buffer, sizeof(tiny_buffer));
    if (result == NULL) {
        if (errno == ERANGE) {
            printf("缓冲区太小错误处理正确: %s\n", strerror(errno));
        } else {
            printf("其他错误: %s\n", strerror(errno));
        }
    }
    
    // 测试无效参数
    result = getcwd(buffer, 0);
    if (result == NULL) {
        if (errno == EINVAL) {
            printf("无效参数处理正确: %s\n", strerror(errno));
        }
    }
    
    // 示例5: 实际应用场景
    printf("\n示例5: 实际应用场景\n");
    
    // 场景1: 程序配置文件定位
    printf("场景1: 程序配置文件定位\n");
    result = getcwd(buffer, sizeof(buffer));
    if (result != NULL) {
        char config_path[PATH_MAX * 2];
        snprintf(config_path, sizeof(config_path), "%s/.myapp/config", buffer);
        printf("配置文件路径: %s\n", config_path);
        
        // 检查配置文件是否存在
        if (access(config_path, F_OK) == 0) {
            printf("配置文件存在\n");
        } else {
            printf("配置文件不存在,将创建默认配置\n");
        }
    }
    
    // 场景2: 相对路径转换为绝对路径
    printf("场景2: 相对路径处理\n");
    const char *relative_paths[] = {"./file.txt", "../parent_dir", "subdir/file"};
    
    for (int i = 0; i < 3; i++) {
        result = getcwd(buffer, sizeof(buffer));
        if (result != NULL) {
            char absolute_path[PATH_MAX * 2];
            snprintf(absolute_path, sizeof(absolute_path), "%s/%s", buffer, relative_paths[i]);
            printf("  %s -> %s\n", relative_paths[i], absolute_path);
        }
    }
    
    // 场景3: 目录操作安全检查
    printf("场景3: 目录操作安全检查\n");
    char current_dir[PATH_MAX];
    char previous_dir[PATH_MAX];
    
    // 保存当前目录
    if (getcwd(current_dir, sizeof(current_dir)) != NULL) {
        printf("当前工作目录: %s\n", current_dir);
        
        // 执行一些目录操作
        // ... 目录操作代码 ...
        
        // 检查目录是否发生变化
        if (getcwd(previous_dir, sizeof(previous_dir)) != NULL) {
            if (strcmp(current_dir, previous_dir) != 0) {
                printf("警告: 工作目录已改变\n");
                printf("原目录: %s\n", current_dir);
                printf("现目录: %s\n", previous_dir);
            } else {
                printf("工作目录保持不变\n");
            }
        }
    }
    
    // 场景4: 日志记录中的目录信息
    printf("场景4: 日志记录\n");
    time_t current_time = time(NULL);
    result = getcwd(buffer, sizeof(buffer));
    if (result != NULL) {
        printf("[%s] INFO: 程序在目录 '%s' 中启动\n", 
               ctime(&current_time), buffer);
    }
    
    // 示例6: 跨平台兼容性考虑
    printf("\n示例6: 跨平台兼容性\n");
    
    // 获取系统路径限制
    long path_max = pathconf(".", _PC_PATH_MAX);
    if (path_max == -1) {
        path_max = PATH_MAX;
        printf("使用默认PATH_MAX: %ld\n", path_max);
    } else {
        printf("系统PATH_MAX: %ld\n", path_max);
    }
    
    // 使用动态分配确保足够空间
    char *safe_buffer = getcwd(NULL, 0);
    if (safe_buffer != NULL) {
        printf("动态分配确保安全: %s\n", safe_buffer);
        printf("路径长度: %zu 字节\n", strlen(safe_buffer));
        free(safe_buffer);
    }
    
    // 示例7: 性能对比测试
    printf("\n示例7: 性能对比测试\n");
    
    // 测试预分配缓冲区的性能
    clock_t start = clock();
    for (int i = 0; i < 10000; i++) {
        getcwd(buffer, sizeof(buffer));
    }
    clock_t preallocated_time = clock() - start;
    
    // 测试动态分配的性能
    start = clock();
    for (int i = 0; i < 10000; i++) {
        char *temp = getcwd(NULL, 0);
        if (temp != NULL) {
            free(temp);
        }
    }
    clock_t dynamic_time = clock() - start;
    
    printf("预分配缓冲区 10000 次调用耗时: %f 秒\n", 
           ((double)preallocated_time) / CLOCKS_PER_SEC);
    printf("动态分配 10000 次调用耗时: %f 秒\n", 
           ((double)dynamic_time) / CLOCKS_PER_SEC);
    printf("预分配方式通常更快\n");
    
    // 清理测试目录
    printf("\n清理测试资源...\n");
    if (access(test_dir, F_OK) == 0) {
        if (rmdir(test_dir) == -1) {
            printf("删除测试目录失败: %s\n", strerror(errno));
        } else {
            printf("删除测试目录完成\n");
        }
    }
    
    return 0;
}
此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注