从C中的路径名中提取基本路径

时间:2011-05-20 15:44:36

标签: c windows file

问题

如何从C中的路径名中提取基本路径?

C语言或C运行时库中是否内置了从C中的路径名中提取基本路径的功能?

我问this问题基本上是相反的。

注意:我更喜欢跨平台解决方案,但我在Windows中工作,所以如果有一个Windows API调用,我仍然想知道。

实施例

Input              | Output
---------------------------------
C:\path\to\file   -> C:\path\to\
C:\path\to\file.c -> C:\path\to\
C:\file           -> C:\
.\file            -> .\
.\                -> .\
\                 -> \

参考

8 个答案:

答案 0 :(得分:6)

在Windows上有_splitpath

实施例

#include <Windows.h>
#include <tchar.h>

// Use your own error codes here
#define SUCCESS                     0L
#define FAILURE_NULL_ARGUMENT       1L
#define FAILURE_API_CALL            2L
#define FAILURE_INSUFFICIENT_BUFFER 3L

DWORD GetBasePathFromPathName( LPCTSTR szPathName,
                               LPTSTR  szBasePath,
                               DWORD   dwBasePathSize )
{
  TCHAR   szDrive[_MAX_DRIVE] = { 0 };
  TCHAR   szDir[_MAX_DIR]     = { 0 };
  TCHAR   szFname[_MAX_FNAME] = { 0 };
  TCHAR   szExt[_MAX_EXT]     = { 0 };
  size_t  PathLength;
  DWORD   dwReturnCode;

  // Parameter validation
  if( szPathName == NULL || szBasePath == NULL )
  {
    return FAILURE_NULL_ARGUMENT;
  }

  // Split the path into it's components
  dwReturnCode = _tsplitpath_s( szPathName, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFname, _MAX_FNAME, szExt, _MAX_EXT );
  if( dwReturnCode != 0 )
  {
    _ftprintf( stderr, TEXT("Error splitting path. _tsplitpath_s returned %d.\n"), dwReturnCode );
    return FAILURE_API_CALL;
  }

  // Check that the provided buffer is large enough to store the results and a terminal null character
  PathLength = _tcslen( szDrive ) + _tcslen( szDir );
  if( ( PathLength + sizeof( TCHAR ) ) > dwBasePathSize )
  {
    _ftprintf( stderr, TEXT("Insufficient buffer. Required %d. Provided: %d\n"), PathLength, dwBasePathSize );
    return FAILURE_INSUFFICIENT_BUFFER;
  }

  // Copy the szDrive and szDir into the provide buffer to form the basepath
  if( ( dwReturnCode = _tcscpy_s( szBasePath, dwBasePathSize, szDrive ) ) != 0 )
  {
    _ftprintf( stderr, TEXT("Error copying string. _tcscpy_s returned %d\n"), dwReturnCode );
    return FAILURE_API_CALL;
  }
  if( ( dwReturnCode = _tcscat_s( szBasePath, dwBasePathSize, szDir ) ) != 0 )
  {
    _ftprintf( stderr, TEXT("Error copying string. _tcscat_s returned %d\n"), dwReturnCode );
    return FAILURE_API_CALL;
  }
  return SUCCESS;
}

答案 1 :(得分:4)

  

C语言或C-Runtime中是否内置了从C中的路径名中提取基本路径的函数?

不,没有。路径名称的规则是特定于平台的,因此标准不包括它们。

答案 2 :(得分:4)

在Windows中,您可以使用API​​调用“PathRemoveFileSpec”http://msdn.microsoft.com/en-us/library/bb773748(v=vs.85).aspx

由于不同操作系统之间的文件系统存在差异,因此无法实现跨平台解决方案。

答案 3 :(得分:2)

WinAPI(shlwapi)PathRemoveFileSpec应该执行所有操作,但.\file除外.

答案 4 :(得分:1)

只需从后向前循环,直到遇到第一个\

答案 5 :(得分:1)

这样做没有标准的C99功能。 POSIX有dirname(),但这对Windows没什么帮助。但是,实现自己的功能应该不会太难;只需搜索字符串,查找最后一次出现的目录分隔符,然后丢弃它后面的任何内容。

答案 6 :(得分:1)

我认为Windows上最好的解决方案是按照建议使用_splitpath,在Linux上使用basename之类的东西(更多关于here)。

那就是说,因为有人已经建议实施我自己的(因为我在等待答案的时候已经完成了),这就是我想出来的。它不是跨平台的,它不检查/ valid / paths或扩展短路径名或相对路径名。

// Retrieves the pathpath from a pathname.
//
// Returns: SUCCESS if the basepath is present and successfully copied to the p_base_path buffer
//          FAILURE_NULL_ARGUMENT if any arguments are NULL
//          FAILURE_INVALID_ARGUMENTS if either buffer size is less than 1
//          FAILURE_BUFFER_TOO_SMALL if the p_basepath buffer is too small
//          FAILURE_INVALID_PATH if the p_pathname doesn't have a path (e.g. C:, calc.exe, ?qwa)
//          FAILURE_API_CALL if there is an error from the underlying API calls
int get_base_path_from_pathname( const char*  const p_pathname,
                                 size_t             pathname_size,
                                 char* const        p_basepath,
                                 size_t             basepath_size );

int get_base_path_from_pathname( const char*  const p_pathname,
                                 size_t             pathname_size,
                                 char* const        p_basepath,
                                 size_t             basepath_size )
{
  char*  p_end_of_path;
  size_t path_length;
  int    return_code;

  // Parameter Validation
  if( p_pathname == NULL || p_basepath == NULL ) { return FAILURE_NULL_ARGUMENT; }
  if( pathname_size < 1 || basepath_size < 1 ) { return FAILURE_INVALID_ARGUMENTS; }

  // Returns a pointer to the last occurrence of \ in p_pathname or NULL if it is not found
  p_end_of_path = strrchr( p_pathname, '\\' );
  if( p_end_of_path == NULL )
  {
    // There is no path part
    return FAILURE_INVALID_PATH;
  } 
  else 
  {
    path_length = (size_t)( p_end_of_path - p_pathname + 1 );

    // Do some sanity checks on the length
    if( path_length < 1 ) { return FAILURE_INVALID_PATH; }
    if( ( path_length + 1 ) > basepath_size ) { return FAILURE_BUFFER_TOO_SMALL; }

    // Copy the base path into the out variable
    if( strncpy( p_basepath, p_pathname, path_length ) != 0 ) { return FAILURE_API_CALL; }
    p_basepath[path_length] = '\0';
  }

  return SUCCESS;
}

答案 7 :(得分:0)

str之前是完整路径和文件名,str之后只是路径:

char dir_ch = '\\'; // set dir_ch according to platform
char str[] = "C:\\path\\to\\file.c";
char *pch = &str[strlen(str)-1];

while(*pch != dir_ch) pch--;
pch++;
*pch = '\0';