微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我一直在尝试在 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,8192,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x7fcadcd6e000
pread64(3,880) = 68
mmap(NULL,2036952,MAP_PRIVATE|MAP_DENYWRITE,0) = 0x7fcadcb7c000
mprotect(0x7fcadcba1000,1847296,PROT_NONE) = 0
mmap(0x7fcadcba1000,1540096,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE,0x25000) = 0x7fcadcba1000
mmap(0x7fcadcd19000,303104,0x19d000) = 0x7fcadcd19000
mmap(0x7fcadcd64000,24576,0x1e7000) = 0x7fcadcd64000
mmap(0x7fcadcd6a000,13528,MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,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,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 上阅读 man here 它说

在 Linux 上,在终端设备上使用 lseek() 失败并显示错误 埃斯皮。

也是错误描述符

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

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

Screenshot of the error case

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)

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

感谢任何和所有帮助。

解决方法

总而言之,我的问题是.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,这在工作区设置中可能特别有用。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。