天天看點

C語言fopen函數的檔案相對路徑到底相對哪?

作者:琴弦第七

C語言怎麼打開檔案?

C語言要打開一個檔案可以使用标準庫的fopen函數,來看下fopen函數的聲明:

FILE *fopen(const char *filename, const char *mode)           

其中,filename參數的類型是字元串,用于指定要打開檔案的路徑,可以是絕對路徑,也可以是相對路徑。mode參數的類型也是字元串,用于指定打開檔案的操作模式,比如"r"(隻讀模式)等等。

那麼,這裡要讨論的是filename參數使用相對路徑的時候,相對位置到底是哪裡呢?

1、源代碼檔案所在路徑?

2、源代碼編譯後的可執行檔案所在路徑?

3、我們自己目前所在的路徑?

你覺得是哪裡?

答案是3,我們自己目前所在的路徑。Show me the code,寫個代碼證明一下。

證明fopen函數相對路徑的位置

建立個新目錄CFileTest,在目錄下面建立main.c源檔案,hello.txt文本檔案,以及build子目錄(存放編譯後的可執行檔案)。目錄結構如下:

CFileTest
  - build
  - hello.txt
  - main.c           

hello.txt隻是一個普通的文本檔案,裡面隻有Hello World字元串。

main.c源代碼的功能也很簡單,就是使用fopen函數打開相對路徑下的hello.txt文本檔案,并列印出檔案内的字元串:

#include <errno.h>
#include <stdio.h>
#include <string.h>

int main() {
  FILE* pFile;
  //以隻讀模式打開相對路徑下的hello.txt檔案
  pFile = fopen("hello.txt", "r");


  //如果檔案打開失敗,列印錯誤碼和錯誤描述
  if (pFile == NULL) {
    int errorCode = errno;
    char* errorMsg = strerror(errorCode);
    printf("Open file fail, errorCode:%d, errorMsg:%s\n", errorCode, errorMsg);
    return -1;
  }

  //如果檔案打開成功,列印出檔案内容
  int c;
  while (1) {
    c = fgetc(pFile);
    if (feof(pFile)) {
      printf("\n");
      break;
    }
    printf("%c", c);
  }

  fclose(pFile);
  return 0;
}           

1、證明相對路徑不是相對于源檔案

現在進入build子目錄,在build子目錄下編譯main.c,并把可執行檔案指定到build目錄:

nan@HWin-Jianan:~/CFileTest$ cd build
nan@HWin-Jianan:~/CFileTest/build$ gcc ../main.c -o main
nan@HWin-Jianan:~/CFileTest/build$ ls -l
total 20
-rwxr-xr-x 1 nan nan 17016 Feb  4 00:14 main           

可以看到在build子目錄下已經生成main可執行檔案,目前的目錄結構如下:

CFileTest
  - build
    - main
  - hello.txt
  - main.c           

在build目錄執行下main可執行檔案:

nan@HWin-Jianan:~/CFileTest/build$ ./main
Open file fail, errorCode:2, errorMsg:No such file or directory           

可以看到hello.txt檔案和main.c源檔案同在一個目錄,但結果卻報錯了,找不到hello.txt這個檔案。說明"hello.txt"這個相對路徑不是相對于源檔案的路徑。

2、證明相對路徑不是相對于可執行檔案所在路徑

把hello.txt檔案移動到build目錄下:

nan@HWin-Jianan:~/CFileTest/build$ mv ../hello.txt ./           

目前目錄結構如下:

CFileTest
  - build
    - hello.txt
    - main
  - main.c           

在build目錄下繼續執行main可執行檔案:

nan@HWin-Jianan:~/CFileTest/build$ ./main
Hello World!           

可以看到成功列印出了hello.txt檔案内容"Hello World",這能确定相對路徑是相對于可執行檔案所在路徑了嗎?别急,别忘了我們自己目前所在路徑也在build目錄下,也有可能是因為相對于我們自己目前所在路徑才成功找到檔案的。那麼,切換下我們自己目前所在的路徑看看,切換到上一級CFileTest目錄再執行看看:

nan@HWin-Jianan:~/CFileTest/build$ cd ..
nan@HWin-Jianan:~/CFileTest$ ./build/main
Open file fail, errorCode:2, errorMsg:No such file or directory           

又找不到檔案了,可以确定相對路徑也不是相對于可執行檔案所在的路徑。

說明:可執行檔案所在路徑不一定就是我們自己目前所在的路徑。比如上面這次實驗,可執行檔案在build目錄下,我們自己目前所在的路徑在CFileTest目錄下。

3、證明相對路徑相對于我們自己目前所在路徑

再次把hello.txt檔案移動到CFileTest目錄下:

nan@HWin-Jianan:~/CFileTest$ mv ./build/hello.txt ./           

移動後目錄結果恢複為:

CFileTest
  - build
    - main
  - hello.txt
  - main.c           

在CFileTest目錄下執行可執行檔案:

nan@HWin-Jianan:~/CFileTest$ ./build/main
Hello World!           

成功找到hello.txt檔案,說明相對路徑是相對于我們自己目前所在路徑的。

就這?有更直接的證據嗎?那就gdb debug模式打個斷點,列印下執行檔案時目前的路徑。

首先重新gcc編譯下源檔案,增加-g參數保留下調試資訊:

nan@HWin-Jianan:~/CFileTest$ gcc -g main.c -o ./build/main           

使用gdb調試main可執行檔案,在源代碼第8行"pFile = fopen("hello.txt", "r");"處打個斷點,然後運作程式到這個斷點:

nan@HWin-Jianan:~/CFileTest$ gdb ./build/main
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
...
Reading symbols from ./build/main...
(gdb) b 8
Breakpoint 1 at 0x1235: file main.c, line 8.
(gdb) r
Starting program: /home/nan/CFileTest/build/main


Breakpoint 1, main () at main.c:8
8         pFile = fopen("hello.txt", "r");           

輸入pwd指令,列印可執行檔案時目前路徑:

(gdb) pwd
Working directory /home/nan/CFileTest.           

可以看到,檔案執行時的工作目錄在CFileTest,與我們自己目前所在的目錄一緻。

總結

C語言的fopen函數,如果指定相對路徑的檔案需要注意一下,相對路徑是相對于我們自己目前所在的路徑,而不是源檔案或者可執行檔案的路徑。