fopen() 无法打开文件

huangapple go评论60阅读模式
英文:

fopen() is unable to open file

问题

我试图打开一个文件并读取其内容。但是,我目前只是试图打开它而已。

这是我的代码:

void read_contents(char* file_path)
{
    printf("\n原始路径:%s\n", file_path);

    // 尝试在路径前面添加"."以表示路径是相对的。
    char prefix[1024] = ".";
    
    strcat(prefix, file_path);

    // 打印以确保前缀包含正确的路径。
    printf("\n连接后的路径:%s\n", prefix);

    FILE* file = fopen(prefix, "r");

    if (file == NULL)
    {
        perror("错误");
        
        // 关闭文件并停止函数。
        fclose(file);
        return;
    }

    // 读取文件的代码...
    // ...
    // 读取文件的代码...

    fclose(file);
}

这是输出结果:(请注意,它甚至没有达到读取部分)

原始路径:/input_files/file_1.txt

连接后的路径:./input_files/file_1.txt

错误:没有这样的文件或目录

这是我的目录结构:

根目录:

可执行文件
input_files(这是一个文件夹)
  file_1.txt

可执行文件位于与名为“input_files”的文件夹相同的级别。在input_files文件夹内是文本文件的位置。

其他注意事项:

  1. 我正在从终端运行正确的可执行文件。
  2. 传递给函数的路径是正确的。
  3. 我的文件夹和文件的结构和名称是正确的。
  4. 访问和读取文件的权限是正确的。
  5. 字符串前面的“.”被正确地添加。

尽管有这些,我仍然收到错误消息,说没有这样的文件或目录。有人能告诉我我漏掉了什么吗?

英文:

I am trying to open a file and read the contents of it. But, I am currently stuck on just trying to open it.

Here is my code:

void read_contents(char* file_path)
{
    printf("\nOriginal path: %s\n", file_path);

    // Trying to prefix the path with "." to indicate that the path is relative.
	char prefix[1024] = ".";
	
	strcat(prefix, file_path);

    // Printing to make sure that prefix contains correct path.
    printf("\nPath after concatenating: %s\n", prefix);

	FILE* file = fopen(prefix, "r");

    if (file == NULL)
    {
	   perror("Error");
	
       // Close the file and stop the function.
       fclose(file);
	   return;
    }


	// Code to read the file...
    // ...
    // Code to read the file...


	fclose(file);
}

Here is the output: (Keep in mind that it does not even reach the reading part)

Original path: /input_files/file_1.txt

Path after concatenating: ./input_files/file_1.txt

Error: no such file or directory

Here is my directory structure:

root:

executable
input_files (this is a folder)
  file_1.txt

The executable is located at the same level as the folder named "input_files". Inside the input_files is where the text file is located.

Additional things:

  1. I am running the correct executable from the terminal.
  2. The path is correct when passing to the function.
  3. The structure and names of my folders and files are correct.
  4. The permissions are correct for accessing and reading files.
  5. The "." is added to the beginning of the string correctly.

With all this I still get an error saying no such file or directory. Can anyone please tell me what I am missing?

答案1

得分: 2

在阅读了所有可能的和常见的解决方案后,如果这些解决方案在您的情况下无效,我唯一的猜测可能是传递给函数的格式不正确的 C 字符串,在第一眼看起来可能是正确的。

我设法在我的项目中复制了类似的问题,只是将格式不正确的 C 字符串指针传递给了 read_contents 函数。

主要思路。
假设您在主函数中有一些静态初始化的数组,其长度比文件路径的长度要长。在我复制的情况下,我取了一个包含 100 个字节的字节数组。

char path2[100] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02};

还有

char path[] = "/file.txt"; // 这个的 strlen 结果为 10(包括 
char path[] = "/file.txt"; // 这个的 strlen 结果为 10(包括 \0)

在我从路径中复制了 9 个字节的内存到 path2 缓冲区之后(不包括 \0)

memcpy(path2, path, 9);

请注意,我已经为 path2 中的 null-terminator 字节准备好了替代值 - 0x02 字节(它可以是任何垃圾值)。从正确的缓冲区复制内存到 path2 缓冲区后,生成的字符串也是正确的,如果我们将其打印出来,我们将看到完全相同的字符串,但是,在 null-terminator 之前的最后一个字节是 0x02,而不是初始路径的最后一个符号。要精确,经过 memcpy 后,path2 缓冲区将如下所示:

2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/  f  i  l  e  .  t  x  t     
2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/  f  i  l  e  .  t  x  t     
2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/  f  i  l  e  .  t  x  t     \0

而不是正确的

2F 66 69 6C 65 2E 74 78 74 00 .... 00
/  f  i  l  e  .  t  x  t  
2F 66 69 6C 65 2E 74 78 74 00 .... 00
/  f  i  l  e  .  t  x  t  
2F 66 69 6C 65 2E 74 78 74 00 .... 00
/  f  i  l  e  .  t  x  t  \0

当尝试打印这个字符串时,你甚至看不到空字符,就好像多余的字节不存在一样,但对于系统来说,这是重要的。

当调用你提供的函数时,我得到了这样的输出:

artyom@artyom:~/workspace/fopenfail$ ./a.out 
Strlen /file.txt = 10
Original path: /file.txt

Path after concatenating: ./file.txt
Error: No such file or directory

artyom@artyom:~/workspace/fopenfail$ ls
a.out  file.txt  main.c
artyom@artyom:~/workspace/fopenfail$ 

以下是我用作可能示例的代码:

void read_contents(char* file_path)
{
    printf("\nOriginal path: %s\n", file_path);

    // 尝试使用"."前缀来表示路径是相对的。
    char prefix[1024] = ".";
    
    strcat(prefix, file_path);
    
    // 打印以确保前缀包含正确的路径。
    printf("\nPath after concatenating: %s\n", prefix);
    
    FILE* file = fopen(prefix, "r");
    
    if (file == NULL)
    {
        perror("Error");
        
        // 关闭文件并停止函数。
        return;
    }

    // 读取文件的代码...
    // ...
    // 读取文件的代码...

    fclose(file);
}

int main()
{
    char path[] = "/file.txt";
    char path2[100] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02};
    memcpy(path2, path, 9);
    printf("Strlen %s = %d", path2, strlen(path2));

    read_contents(path2);
    return EXIT_SUCCESS;
}

希望这将作为提示,指出调用函数中的问题。

英文:

After reading all possible and common solutions in this kind of cases, which didn't work in your case, my only guess can be the malformed C-string passed to function, which can be treated as correct at a first glance.
I managed to reproduce the similar problem at my site only having malformed C-string pointer passed to read_contents function.

The main idea.
Let's say you have some statically initialized array in your main function which length is more than that of path of file. In my reproduced case I took byte array with 100 bytes in it.

char path2[100] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x02};

also I have

char path[] = "/file.txt" // strlen on this will result in 10 (includes 
char path[] = "/file.txt" // strlen on this will result in 10 (includes \0)
)

After I copy the 9 bytes of memory to path2 buffer from path (excluding \0)

memcpy(path2, path, 9);

Note that I already prepared the replacement for null-terminator byte in path2 - 0x02 byte (it may be any garbage value)
After copying the memory from correct buffer to path2 buffer. The resulting string is also correct and if we print it out we see exactly the same string, but, the last byte before null-terminator is 0x02 and not the last symbol from initial path.
To be precise the path2 buffer will look like this after memcpy.

2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/  f  i  l  e  .  t  x  t     
2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/  f  i  l  e  .  t  x  t     
2F 66 69 6C 65 2E 74 78 74 02 00 .... 00
/  f  i  l  e  .  t  x  t     \0

instead of correct

2F 66 69 6C 65 2E 74 78 74 00 .... 00
/  f  i  l  e  .  t  x  t  
2F 66 69 6C 65 2E 74 78 74 00 .... 00
/  f  i  l  e  .  t  x  t  
2F 66 69 6C 65 2E 74 78 74 00 .... 00
/  f  i  l  e  .  t  x  t  \0

When try to print out this string you won't even see empty char, as if spare byte does not exist, but for system it matters C:

When invoking your provided function I get this kind of output

artyom@artyom:~/workspace/fopenfail$ ./a.out 
Strlen /file.txt = 10
Original path: /file.txt

Path after concatenating: ./file.txt
Error: No such file or directory

artyom@artyom:~/workspace/fopenfail$ ls
a.out  file.txt  main.c
artyom@artyom:~/workspace/fopenfail$ 

Here is the code I used as possible example

void read_contents(char* file_path)
{
    printf("\nOriginal path: %s\n", file_path);

    // Trying to prefix the path with "." to indicate that the path is relative.
    char prefix[1024] = ".";

    strcat(prefix, file_path);

    // Printing to make sure that prefix contains correct path.
    printf("\nPath after concatenating: %s\n", prefix);

    FILE* file = fopen(prefix, "r");

    if (file == NULL)
    {
       perror("Error");

       // Close the file and stop the function.
       return;
    }


    // Code to read the file...
    // ...
    // Code to read the file...


    fclose(file);
}

int main()
{
        char path[] = "/file.txt";
        char path2[100] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x02};
        memcpy(path2, path, 9);
        printf("Strlen %s = %d", path2, strlen(path2));

        read_contents(path2);
        return EXIT_SUCCESS;
}

Hope this will serve as hint what is wrong in caller function.

答案2

得分: 1

我无法重现这个错误,这很可能意味着你的当前工作目录与预期的不同。以下是你应该提供的程序,而不是一个不完整的代码片段,它将打印出当前工作目录(cwd):

#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void read_contents(char* file_path) {
    printf("原始路径:%s\n", file_path);
    char prefix[strlen(file_path) + 2];
    strcpy(prefix, ".");
    strcat(prefix, file_path);
    printf("连接后的路径:%s\n", prefix);
    FILE* file = fopen(prefix, "r");
    if (!file) {
        perror("错误");
        char cwd[PATH_MAX];
        getcwd(cwd, PATH_MAX);
        printf("cwd:%s\n", cwd);
        return;
    }
    fclose(file);
}

int main(void) {
    read_contents("/input_files/file_1.txt");
    read_contents("/input_files/non-existing.txt");
}

这是一个示例运行:

原始路径:/input_files/file_1.txt
连接后的路径:./input_files/file_1.txt
原始路径:/input_files/non-existing.txt
连接后的路径:./input_files/non-existing.txt
错误:没有这个文件或目录
cwd:/home/...
英文:

I can't reproduce the error which likely means your current working directory is probably different than expected. Here is the program you should have provided instead of an incomplete snippet that will print out the current working directory (cwd):

#include &lt;limits.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;unistd.h&gt;

void read_contents(char* file_path) {
	printf(&quot;Original path: %s\n&quot;, file_path);
	char prefix[strlen(file_path)+2];
	strcpy(prefix, &quot;.&quot;);
	strcat(prefix, file_path);
	printf(&quot;Path after concatenating: %s\n&quot;, prefix);
	FILE* file = fopen(prefix, &quot;r&quot;);
	if (!file) {
		perror(&quot;Error&quot;);
		char cwd[PATH_MAX];
		getcwd(cwd, PATH_MAX);
		printf(&quot;cwd: %s\n&quot;, cwd);
		return;
	}
	fclose(file);
}

int main(void) {
	read_contents(&quot;/input_files/file_1.txt&quot;);
	read_contents(&quot;/input_files/non-existing.txt&quot;);
}

and here is an example run:

Original path: /input_files/file_1.txt
Path after concatenating: ./input_files/file_1.txt
Original path: /input_files/non-existing.txt
Path after concatenating: ./input_files/non-existing.txt
Error: No such file or directory
cwd: /home/...

huangapple
  • 本文由 发表于 2023年6月26日 08:45:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76552943.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定