【问题标题】:fopen() returns NULL but open() syscall returns proper file descriptor?fopen() 返回 NULL 但 open() 系统调用返回正确的文件描述符?
【发布时间】:2021-06-24 09:40:36
【问题描述】:

我一直在尝试在 Ubuntu 20.04LTS 上运行这个非常简单的 C 代码

#include<stdio.h>
#include<stdlib.h>

int main()
{
   
    FILE *f;
   
    f=fopen("tree.txt","r");
    if(f==NULL){
        perror("fopen");
        exit(1);
    }
    //readTree();
    return 0;
}

但是到目前为止,无论我尝试了什么,fopen 仍然返回此错误:

fopen: No such file or directory
[1] + Done     

我首先假设程序没有打开文件的权限,但是权限设置正确:

ls -la tree.txt
-rw-rw-rw- 1 mor mor 7 mar 26 20:43 tree.txt

接下来我尝试将文件的位置更改为 /home 或指定完整路径而不是文件名;结果还是一样

现在是我无法理解的部分,在 Strace 下运行脚本时,它似乎工作正常,至少现在是这样

execve("./B1", ["./B1"], 0x7ffe586e59b0 /* 26 vars */) = 0
brk(NULL)                               = 0x55cd150ea000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff084d4590) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=156877, ...}) = 0
mmap(NULL, 156877, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcadcd70000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360q\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2029224, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcadcd6e000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
mmap(NULL, 2036952, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcadcb7c000
mprotect(0x7fcadcba1000, 1847296, PROT_NONE) = 0
mmap(0x7fcadcba1000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7fcadcba1000
mmap(0x7fcadcd19000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7fcadcd19000
mmap(0x7fcadcd64000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7fcadcd64000
mmap(0x7fcadcd6a000, 13528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcadcd6a000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7fcadcd6f540) = 0
mprotect(0x7fcadcd64000, 12288, PROT_READ) = 0
mprotect(0x55cd14c84000, 4096, PROT_READ) = 0
mprotect(0x7fcadcdc4000, 4096, PROT_READ) = 0
munmap(0x7fcadcd70000, 156877)          = 0
brk(NULL)                               = 0x55cd150ea000
brk(0x55cd1510b000)                     = 0x55cd1510b000
openat(AT_FDCWD, "tree.txt", O_RDONLY)  = 3
exit_group(0)                           = ?
+++ exited with 0 +++

openat() 调用返回一个小的正整数,这是我目前所读到的正常行为

最后,真正让我大吃一惊的是 上面 Strace 的输出与我几分钟前收到的输出不同。出于某种原因,我似乎无法重新创建该输出,但它的要点是:

-openat() 返回 3

-lseek(fd, -9, SEEK_CUR) 被调用并返回 -1 ESPIPE Illegal seek 请原谅我的语法,我是凭记忆写的。 另外为什么偏移量是负整数?这正常吗?

为什么前几次调用了 lseek(),但现在没有?

在 lseek here 上阅读的人这么说

在 Linux 上,在终端设备上使用 lseek() 失败并出现错误 ESPIPE。

也是错误描述符

ESPIPE fd 与管道、套接字或 FIFO 相关联。

我相信第一句话是不相关的,网上有很多线程,人们设法在 linux 上使用 fopen()。说到错误描述符,就超出了我的理解水平。

renderer1.log:

[2021-03-27 23:08:46.895] [renderer1] [error] Unexpected: The specified task is missing an execution: Error: Unexpected: The specified task is missing an execution
    at S.getTaskExecution (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:48749)
    at S.$onDidStartTaskProcess (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:46905)
    at c._doInvokeHandler (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:10509)
    at c._invokeHandler (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:10201)
    at c._receiveRequest (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:8871)
    at c._receiveOneMessage (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:7673)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:5782
    at g.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:57:1836)
    at p.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:15443)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:106:29119
    at g.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:57:1836)
    at p.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:15443)
    at t._receiveMessage (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:20693)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:17587
    at g.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:57:1836)
    at l.acceptChunk (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:12808)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:12156
    at Socket.E (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:106:12375)
    at Socket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:295:12)
    at readableAddChunk (_stream_readable.js:271:9)
    at Socket.Readable.push (_stream_readable.js:212:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:186:23)

我能想到的就这些了,显然还不够好。

感谢任何和所有的帮助。

【问题讨论】:

  • 您的帖子中没有任何内容描述实际的错误情况 - 您的代码很好,您的目录列表看起来很好,并且您向我们发送了工作条件的痕迹。您能否提供更多关于失败案例的详细信息以帮助我们理解?
  • 您是通过 IDE 运行它吗?这种情况下的一个常见问题是文件没有放在 IDE 的工作目录中。请更清楚地描述您是如何运行代码的 - 显示构建代码、运行程序并列出目录的全部内容的确切日志。
  • lseek() 调用的文件描述符是 0,而不是文件的 3。通话检查stdin
  • 您是否尝试从命令行运行程序,文件位于当前目录中?
  • 注意:使用绝对路径只是一个测试。在实际代码中不会这样做,因为这样的硬编码会使代码过于僵化 - 它会在其他环境中中断。另外,请随时回答您自己的问题。

标签: c ubuntu visual-studio-code fopen lseek


【解决方案1】:

总而言之,我的问题是 .c 程序的工作目录和我保存 .txt 文件的目录不同。有很多方法可以解决这个问题。

尝试在 fopen 目录中使用绝对路径。例如:

    FILE*f; f=fopen("/home/user/Desktop/file.txt","r");
 

这仅作为测试,因为它使代码过于僵化(@kaylum 提供的答案)

使用chdir() 更改工作目录

将目录更改为用户指定的目录的简单代码,以用户指定的名称和模式打开文件;使用getcwd() 打印 cwd (部分答案由@ilkkachu 提供)

//puts cwd in *str and prints cwd if successful, otherwise prints error 
void getdir(char *str, unsigned int str_size)
{
    
     if(getcwd(str,str_size)==NULL){
        perror("getcwd()");
        exit(1);
    }else
        printf("Current working dir: %s\n",str);
}

//reads directory path and sets it as new working dir
int changeDir()
{
    char cwd[256];
    printf("New woking dir path= ");
    scanf("%s",cwd);
    if(chdir(cwd)!=0){
        perror("chdir()");
        return -1;
        }
    getdir(cwd,sizeof(cwd));
    return 0;
}

int main()
{
   
    FILE *f;
    char cwd[256],fmod[5];
    
    getdir(cwd,sizeof(cwd));
    //reads new path until an existing one is inputted
    while(changeDir()!=0);

    printf("File name: ");
    scanf("%s",cwd);
    printf("File mode: ");
    scanf("%s",fmod);
    
    f=fopen(cwd,fmod);
    if(f==NULL){
        perror("fopen");
        exit(1);
    }


    //reads first line of file and prints it to console
    fscanf(f,"%[^\n]",cwd);
    printf("%s",cwd);
    
    return 0;
}

代码终端输出:

Current working dir: /home/moro/Documents/TP-Lab
New woking dir path= /home/moro/doesNotExist
chdir(): No such file or directory
New woking dir path= /home/moro/Desktop
Current working dir: /home/moro/Desktop
File name: input.txt
File mode: r
THIS IS A TEST FILE[1] + Done

        

在 Visual Studio Code 设置中更改当前工作目录

前往

设置>终端>集成:Cwd

你可以在那里指定起始路径

终端 › 集成:Cwd 将启动终端的显式启动路径,用作 shell 进程的当前工作目录 (cwd)。如果根目录不是方便的 cwd,这在工作区设置中可能特别有用。

可能有更流畅的方法来解决这个问题,但对于我的用例来说,这些选项已经足够好了。如果我有时间,我会为这个答案添加更多解决方案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 2023-04-07
    • 2011-10-04
    • 1970-01-01
    相关资源
    最近更新 更多