简体   繁体   English

fopen() 返回 NULL 但 open() 系统调用返回正确的文件描述符?

[英]fopen() returns NULL but open() syscall returns proper file descriptor?

I've been trying to run this very simple C code on Ubuntu 20.04LTS我一直在尝试在 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;
}

But no matter what I've tried so far fopen still returns this eror:但无论我到目前为止尝试了什么 fopen 仍然返回这个错误:

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

First thing I assumed was that the program didn't have permission to open the file, but the permissions are set correctly:我假设的第一件事是程序没有打开文件的权限,但权限设置正确:

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

Next I tried to change the location of the file to /home or to specify a full path instead of the file name;接下来我尝试将文件的位置更改为 /home 或指定完整路径而不是文件名; still the same result还是一样的结果

Now comes the part I can't wrap my head around, when running the script under Strace, it appears to work fine , at least for now现在是我无法理解的部分,在 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 +++

The openat() call returns a small positive integer, which is normal behavior from what I read so far openat() 调用返回一个小的正数 integer,这是我目前阅读的正常行为

Lastly, what really grinds my gears is that the output of Strace above differs from the output I received just a couple minutes before .最后,真正让我印象深刻的是,上面 Strace 的 output 与我几分钟前收到的 output 不同 For some reason I can't seem to recreate that output but the gist of it is this:出于某种原因,我似乎无法重新创建 output 但它的要点是:

-openat() returns 3 -openat() 返回 3

- lseek(fd, -9, SEEK_CUR) is called and returns -1 ESPIPE Illegal seek please excuse my syntax here, I'm writing it from memory. - lseek(fd, -9, SEEK_CUR)被调用并返回-1 ESPIPE 非法搜索请原谅我的语法,我是从 memory 写的。 Also why is the offset a negative integer?另外为什么偏移量是负 integer? Is that normal?这正常吗?

And why was lseek() called the first couple of times, but not now?为什么 lseek() 前几次被调用,但不是现在?

Reading man on lseek here it says that这里阅读 lseek 上的 man 它说

On Linux, using lseek() on a terminal device fails with the error ESPIPE.在 Linux 上,在终端设备上使用 lseek() 失败并出现错误 ESPIPE。

also the error descriptor还有错误描述符

ESPIPE fd is associated with a pipe, socket, or FIFO. ESPIPE fd 与 pipe、套接字或 FIFO 相关联。

I believe the first quote to be unrelated, plenty of threads online with people managing to use fopen() on linux.我相信第一个引用是不相关的,网上有很多线程,人们设法在 linux 上使用 fopen()。 When it comes to the error descriptor, it is beyond my level of understanding.当涉及到错误描述符时,它超出了我的理解水平。

错误案例截图

renderer1.log:渲染器1.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)

This is all I could come up with, apparently it's not good enough.这就是我能想到的,显然它还不够好。

Any and all help is appreciated.任何和所有的帮助表示赞赏。

To sum it up, my issue was that the working directory of the.c program and the directory in which i had saved the.txt file were different.总结一下,我的问题是.c程序的工作目录和我保存.txt文件的目录不同。 There are many ways to get around this issue.有很多方法可以解决这个问题。

Try using an absolute path in the fopen directory.尝试在 fopen 目录中使用绝对路径。 For example:例如:

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

this only works as a test, as it makes the code too rigid(answer provided by @kaylum)这仅作为测试起作用,因为它使代码过于僵化(@kaylum 提供的答案)

Changing the working directory using chdir()使用chdir()更改工作目录

simple code that changes directory to the one specified by the user, opens file with name and mode specified by user;将目录更改为用户指定的目录的简单代码,以用户指定的名称和模式打开文件; printing cwd using getcwd() (part of the answer provided by @ilkkachu)使用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;
}

Code terminal output:编码端子output:

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

        

Changing the current working directory in Visual Studio Code settings在 Visual Studio Code 设置中更改当前工作目录

Go to Go 至

Settings>Terminal>Integrated: Cwd设置>终端>集成:Cwd

You can specify a start path there您可以在那里指定起始路径

Terminal › Integrated: Cwd An explicit start path where the terminal will be launched, this is used as the current working directory (cwd) for the shell process.终端 › 集成:Cwd 将启动终端的显式启动路径,用作 shell 进程的当前工作目录 (cwd)。 This may be particularly useful in workspace settings if the root directory is not a convenient cwd.如果根目录不是方便的 cwd,这在工作区设置中可能特别有用。

There probably are smoother ways to go about this, but for my use case these options are more than good enough. go 可能有更流畅的方法,但对于我的用例来说,这些选项已经足够好了。 If i find the time i will add more solutions to this answer如果我有时间,我会为这个答案添加更多解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM