【问题标题】:Opening a file using relative path使用相对路径打开文件
【发布时间】:2016-09-11 02:28:29
【问题描述】:

以下代码应该按如下方式工作:打印目录中的文件列表,并打印每个 .c 文件的内容。 在 UNIX 中针对同一目录执行时,它可以正常工作:./a.out ./

但是,我无法使其适用于 ./a.out ../differentDir 执行。

我知道,如果绝对路径作为参数提供,我可以使用 argv[1] 。但是,当它以相对路径的形式提供时,我会迷路。

#include <sys/types.h>

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUFFSIZE 32768

int main(int argc, char **argv) {

    char buf[BUFFSIZE];
    DIR *dp;
    struct dirent *dirp;
    char filename[80];
    int  name_length;
    FILE *fp;

    if (argc != 2) {
        fprintf(stderr, "usage: %s dir_name\n", argv[0]);
        exit(1);
    }

    if ((dp = opendir(argv[1])) == NULL ) {
        fprintf(stderr, "can't open '%s'\n", argv[1]);
        exit(1);
    }

        while ((dirp = readdir(dp)) != NULL ){
           printf("%s\n", dirp->d_name);
           memset(filename, '\0', sizeof(filename));
           strcpy(filename, dirp->d_name);
           printf(" ** %s ", filename);
           name_length = strlen(filename);
           printf(" name_length=%d \n", name_length);
            if (findC(filename)) // checking if the file has a .c extension
            {
                fp=fopen(filename, "r");
                if (fp == NULL)
                    fprintf(stderr, "Can't open .C file!\n");
                else
                    {// if the file was opened successfuly:
                        do
                        {
                           fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
                           buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
                           puts(buf);
                        }
                        while (!feof(fp));
                    printf("\n\n");
                    fclose(fp);
                    }
            }
        }
    closedir(dp);
    return(0);
}

/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
    int len = strlen(name);
    if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
        return 1;
    return 0;
}

【问题讨论】:

  • 附带问题:fgets(buf,BUFFSIZE,fp); buf[strlen(buf)-1]='\0'; 可能导致未定义的行为。 1) 在使用buf 之前检查fgets() 的结果。 2) 在使用buf[strlen(buf)-1]='\0' 之前确保strlen(buf) &gt; 0。 (很少需要,但确实可以防止 UB)。
  • 谢谢,好点子!这样会更好: if (fgets(buf,BUFFSIZE,fp)!=NULL) { buf[strlen(buf)-1]='\0';放(buf); }
  • 代码失败,因为fopen(filename... 不考虑argv[1]
  • 使用buf[strcspn(buf, "\n')] = 0; 去除潜力\nbuf[strlen(buf)-1]='\0'; 在上面的评论中仍然失败了#2。
  • 这就是我提到的问题。如果我的可执行文件在同一个目录中,它工作正常。但是,如果我想打印另一个目录,我需要以某种方式获取绝对路径。由于某种原因,realpath() 方法对我不起作用(请参阅我对@Dac Saunders 的回复)。

标签: c unix path


【解决方案1】:

打开要读取的文件时,文件路径名也需要是相对的。

    // Form prefix for complete relative file name
    char filename[MAXPATH];
    strcpy(filename, argv[1]);
    // append '/' if directory path does not end in '/'
    if (TBD_code(filename)) {
      strcat(filename, "/");
    }
    char *end = filename[strlen(filename)];

    while ((dirp = readdir(dp)) != NULL ){
       printf("%s\n", dirp->d_name);
       if (findC(dirp->d_name)) {
         // append filename to prefix
         strcpy(end, dirp->d_name);
         fp=fopen(filename, "r");
         ...

【讨论】:

  • 我按照您的建议使用了类似的版本,但是当我在相对路径上运行它时,它无法打开文件。 $ ./lsc ../dir ** . name_length=1 .. ** .. name_length=2 b.html ** b.html name_length=6 practice.txt ** practice.txt name_length=12 A.c ** A.c name_length=3 Can't open .C file! 的输出
  • @DR29 当fp=fopen(filename, "r"); 失败时filename 的值是多少?
  • "../dir/file.txt" 是值(我添加了 puts 语句来验证)。
【解决方案2】:

您可以像本例中一样使用@987654321@@987654322@...)realpath 将返回相对路径的绝对路径。

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv) {
    char *path = "../..";
    char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
    char *res = realpath(path, buff);
    if (res) {
        printf("This source is at %s.\n", buff);
    } else {
        perror("realpath");
        exit(EXIT_FAILURE);
    }
    return 0;
}

要在您的程序中包含所需的行为,您可以在代码中使用realpath

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>

#define BUFFSIZE 32768

int main(int argc, char **argv) {

    char buf[BUFFSIZE];
    DIR *dp;
    struct dirent *dirp;
    char filename[80];
    int  name_length;
    FILE *fp;
    char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */

    if (argc != 2) {
        fprintf(stderr, "usage: %s dir_name\n", argv[0]);
        exit(1);
    }
    char *res = realpath(argv[1], buff);
    if ((dp = opendir(res)) == NULL ) {
        fprintf(stderr, "can't open '%s'\n", argv[1]);
        exit(1);
    }

    while ((dirp = readdir(dp)) != NULL ){
        printf("%s\n", dirp->d_name);
        memset(filename, '\0', sizeof(filename));
        strcpy(filename, dirp->d_name);
        printf(" ** %s ", filename);
        name_length = strlen(filename);
        printf(" name_length=%d \n", name_length);
        if (findC(filename)) // checking if the file has a .c extension
        {
            fp=fopen(filename, "r");
            if (fp == NULL)
                fprintf(stderr, "Can't open .C file!\n");
            else
            {// if the file was opened successfuly:
                do
                {
                    fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
                    buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
                    puts(buf);
                }
                while (!feof(fp));
                printf("\n\n");
                fclose(fp);
            }
        }
    }
    closedir(dp);
    return(0);
}

/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
    int len = strlen(name);
    if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
        return 1;
    return 0;
}

【讨论】:

  • 我不确定它有什么问题,但是当我编译时我得到“未定义的对 realpath 的引用”。
  • @DR29 这可能取决于您的环境和操作系统。我用 Ubuntu Linux 对其进行了测试。您是否包含stdlib.h
  • 是的,我做到了。我实际上是在 Windows 上编写它并尝试在 unix ssh 服务器上运行代码。
  • 什么语言标准定义了realpath()
【解决方案3】:

您可以先使用相对路径或绝对路径切换到目录chdir,然后通过getcwd获取绝对路径

#include <sys/types.h>

#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUFFSIZE 32768
#define PATH_SIZE 512

int main(int argc, char **argv) {

    char buf[BUFFSIZE];
    char path[PATH_SIZE];
    DIR *dp;
    struct dirent *dirp;
    char filename[80];
    int  name_length, r;
    FILE *fp;

    if (argc != 2) {
        fprintf(stderr, "usage: %s dir_name\n", argv[0]);
        exit(1);
    }
    
    strcpy(path, argv[1]);
    r = chdir(path);
    if( r != 0 )
    {
        printf("Invalid path '%s'\n",path);
        exit(1);
    }
    getcwd(path,PATH_SIZE);

    if ((dp = opendir(path)) == NULL ) {
        fprintf(stderr, "can't open '%s'\n", argv[1]);
        exit(1);
    }

        while ((dirp = readdir(dp)) != NULL ){
           printf("%s\n", dirp->d_name);
           memset(filename, '\0', sizeof(filename));
           strcpy(filename, dirp->d_name);
           printf(" ** %s ", filename);
           name_length = strlen(filename);
           printf(" name_length=%d \n", name_length);
            if (findC(filename)) // checking if the file has a .c extension
            {
                fp=fopen(filename, "r");
                if (fp == NULL)
                    fprintf(stderr, "Can't open .C file!\n");
                else
                    {// if the file was opened successfuly:
                        do
                        {
                           fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
                           buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
                           puts(buf);
                        }
                        while (!feof(fp));
                    printf("\n\n");
                    fclose(fp);
                    }
            }
        }
    closedir(dp);
    return(0);
}

/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
    int len = strlen(name);
    if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
        return 1;
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 2017-09-05
    • 2016-03-21
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    相关资源
    最近更新 更多