Извлечь базовый путь из пути в C - PullRequest
6 голосов
/ 20 мая 2011

Вопрос

Как извлечь базовый путь из пути в C?

Существуют ли какие-либо функции, встроенные в язык C или C-Runtime Library для извлечения базового пути из пути в C?

Я задаю в основном противоположность этого вопроса.

ПРИМЕЧАНИЕ. Я предпочитаю кроссплатформенное решение, но я работаю в 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 ]

6 голосов
/ 20 мая 2011

В 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;
}
4 голосов
/ 20 мая 2011

В Windows вы можете использовать вызов API «PathRemoveFileSpec» http://msdn.microsoft.com/en-us/library/bb773748(v=vs.85).aspx

Кроссплатформенные решения не будут действительно возможны из-за различий в файловых системах между различными ОС.

4 голосов
/ 20 мая 2011

Существуют ли какие-либо функции, встроенные в язык C или C-Runtime для извлечения базового пути из пути в C?

Нет, нет. Правила для имен путей зависят от платформы, поэтому стандарт не распространяется на них.

2 голосов
/ 20 мая 2011

WinAPI (shlwapi) PathRemoveFileSpec должен делать все это, за исключением .\file, который возвращается как .

1 голос
/ 20 мая 2011

Я думаю, что лучшее решение для Windows - использовать _splitpath , как было предложено, использовать что-то вроде basename в Linux (подробнее об этом здесь ).

Тем не менее, поскольку кто-то уже предложил внедрить мой собственный (и поскольку я уже сделал это, пока ждал ответа), вот что я придумала. Он не кроссплатформенный и не проверяет / 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;
}
1 голос
/ 20 мая 2011

Для этого нет стандартной функции C99.POSIX имеет dirname(), но это не сильно поможет вам в Windows.Однако вам не должно быть слишком сложно реализовать свою собственную функцию;просто ищите строку, ищите последнее вхождение разделителя каталогов и отбрасывайте что-либо после него.

1 голос
/ 20 мая 2011

Просто переходите от одного к другому, пока не встретите первое \

0 голосов
/ 20 мая 2011

До 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';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...