簡體   English   中英

如何獲取*不*存在的文件或目錄的絕對路徑?

[英]How to get absolute path of file or directory, that does *not* exist?

在 GNU/Linux 上,如何從 C/C++ 中給定的相對路徑確定文件或目錄的絕對路徑?
我知道realpath() ,但它不適用於不存在的文件。

假設用戶輸入../non-existant-directory/file.txt ,程序工作目錄是/home/user/
我需要的是返回 /home/non-existant-directory/file.txt 的/home/non-existant-directory/file.txt

我需要這個 function 來檢查給定路徑是否在某個子目錄中。

嘗試realpath 如果失敗,則開始一次從末尾刪除路徑組件並重試realpath直到成功。 然后將您刪除的組件附加到成功的realpath調用的結果中。

如果您確定包含的目錄存在並且您只想在那里創建一個文件,那么您最多只需要刪除一個組件。

另一種方法是先創建文件,然后調用realpath

正如@R.. GitHub 所指出的,您可以在realpath()上構建此功能。 這是一個示例函數,它使用realpath()來確定存在的路徑部分的規范形式,並將路徑的不存在部分附加到它。

由於realpath()對 C 風格的字符串進行操作,因此我決定在這里也使用它們。 但是這個函數可以很容易地被重寫為使用std::string (只是不要忘記在將它復制到std::string之后釋放canonical_file_path 。)。

請注意,不會從不存在的路徑部分中刪除重復的“/”條目; 它只是附加到確實存在的部分的規范形式。

////////////////////////////////////////////////////////////////////////////////
// Return the input path in a canonical form. This is achieved by expanding all
// symbolic links, resolving references to "." and "..", and removing duplicate
// "/" characters.
//
// If the file exists, its path is canonicalized and returned. If the file,
// or parts of the containing directory, do not exist, path components are
// removed from the end until an existing path is found. The remainder of the
// path is then appended to the canonical form of the existing path,
// and returned. Consequently, the returned path may not exist. The portion
// of the path which exists, however, is represented in canonical form.
//
// If successful, this function returns a C-string, which needs to be freed by
// the caller using free().
//
// ARGUMENTS:
//   file_path
//   File path, whose canonical form to return.
//
// RETURNS:
//   On success, returns the canonical path to the file, which needs to be freed
//   by the caller.
//
//   On failure, returns NULL.
////////////////////////////////////////////////////////////////////////////////
char *make_file_name_canonical(char const *file_path)
{
  char *canonical_file_path  = NULL;
  unsigned int file_path_len = strlen(file_path);

  if (file_path_len > 0)
  {
    canonical_file_path = realpath(file_path, NULL);
    if (canonical_file_path == NULL && errno == ENOENT)
    {
      // The file was not found. Back up to a segment which exists,
      // and append the remainder of the path to it.
      char *file_path_copy = NULL;
      if (file_path[0] == '/'                ||
          (strncmp(file_path, "./", 2) == 0) ||
          (strncmp(file_path, "../", 3) == 0))
      {
        // Absolute path, or path starts with "./" or "../"
        file_path_copy = strdup(file_path);
      }
      else
      {
        // Relative path
        file_path_copy = (char*)malloc(strlen(file_path) + 3);
        strcpy(file_path_copy, "./");
        strcat(file_path_copy, file_path);
      }

      // Remove path components from the end, until an existing path is found
      for (int char_idx = strlen(file_path_copy) - 1;
           char_idx >= 0 && canonical_file_path == NULL;
           --char_idx)
      {
        if (file_path_copy[char_idx] == '/')
        {
          // Remove the slash character
          file_path_copy[char_idx] = '\0';

          canonical_file_path = realpath(file_path_copy, NULL);
          if (canonical_file_path != NULL)
          {
            // An existing path was found. Append the remainder of the path
            // to a canonical form of the existing path.
            char *combined_file_path = (char*)malloc(strlen(canonical_file_path) + strlen(file_path_copy + char_idx + 1) + 2);
            strcpy(combined_file_path, canonical_file_path);
            strcat(combined_file_path, "/");
            strcat(combined_file_path, file_path_copy + char_idx + 1);
            free(canonical_file_path);
            canonical_file_path = combined_file_path;
          }
          else
          {
            // The path segment does not exist. Replace the slash character
            // and keep trying by removing the previous path component.
            file_path_copy[char_idx] = '/';
          }
        }
      }

      free(file_path_copy);
    }
  }

  return canonical_file_path;
}

你可以嘗試做這樣的事情:

let pbuf = std::path::PathBuf::from_str("somewhere/something.json").unwrap();
let parent = pbuf.parent().unwrap().canonicalize().unwrap_or(std::env::current_dir().unwrap());
let file = pbuf.file_name().unwrap().to_str().unwrap();
let final_path = parent.join(file).to_str().unwrap().to_owned();

如果父路徑不存在(或由於任何原因失敗),它將附加當前目錄到它的位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM