Как я могу извлечь имя файла и расширение из пути в C ++ - PullRequest
63 голосов
/ 13 декабря 2010

У меня есть список файлов, сохраненных в .log с этим синтаксисом:

c:\foto\foto2003\shadow.gif
D:\etc\mom.jpg

Я хочу извлечь имя и расширение из этих файлов. Можете ли вы привести пример простого способа сделать это?

Ответы [ 8 ]

153 голосов
/ 17 февраля 2014

Чтобы извлечь имя файла без расширения, используйте boost :: filesystem :: path :: stem вместо безобразного std :: string :: find_last_of (".")

boost::filesystem::path p("c:/dir/dir/file.ext");
std::cout << "filename and extension : " << p.filename() << std::endl; // file.ext
std::cout << "filename only          : " << p.stem() << std::endl;     // file
19 голосов
/ 13 декабря 2010

Если вы хотите безопасный способ (т. Е. Переносить между платформами и не ставить предположения на пути), я бы рекомендовал использовать boost::filesystem.

Это будет выглядеть примерно так:

boost::filesystem::path my_path( filename );

Затем вы можете извлечь различные данные из этого пути. Вот документация объекта пути.


Кстати: также помните, что для использования пути, как

c:\foto\foto2003\shadow.gif

вам нужно экранировать \ в строковом литерале:

const char* filename = "c:\\foto\\foto2003\\shadow.gif";

Или используйте / вместо:

const char* filename = "c:/foto/foto2003/shadow.gif";

Это относится только к указанию буквенных строк в "" кавычках, проблема не возникает при загрузке путей из файла.

14 голосов
/ 13 декабря 2010

Вам нужно будет прочитать ваши имена файлов из файла в std::string.Вы можете использовать оператор извлечения строки std::ostream.Если у вас есть имя файла в std::string, вы можете использовать метод std::string::find_last_of, чтобы найти последний разделитель.

Примерно так:

std::ifstream input("file.log");
while (input)
{
    std::string path;
    input >> path;

    size_t sep = path.find_last_of("\\/");
    if (sep != std::string::npos)
        path = path.substr(sep + 1, path.size() - sep - 1);

    size_t dot = path.find_last_of(".");
    if (dot != std::string::npos)
    {
        std::string name = path.substr(0, dot);
        std::string ext  = path.substr(dot, path.size() - dot);
    }
    else
    {
        std::string name = path;
        std::string ext  = "";
    }
}
12 голосов
/ 19 июля 2016

Для C ++ 17 :

#include <filesystem>

std::filesystem::path p("c:/dir/dir/file.ext");
std::cout << "filename and extension: " << p.filename() << std::endl; // "file.ext"
std::cout << "filename only: " << p.stem() << std::endl;              // "file"

Справка о файловой системе: http://en.cppreference.com/w/cpp/filesystem


По предложению @ RoiDanto , для форматирования вывода std::out может окружать вывод кавычками, например:

filename and extension: "file.ext"

Вы можете преобразовать std::filesystem::path в std::string на p.filename().string(), если это то, что вам нужно, например:

filename and extension: file.ext
3 голосов
/ 13 декабря 2010

Не код, но вот идея:

  1. Считывание std::string из входного потока (std::ifstream), каждый прочитанный экземпляр будет полным путем
  2. Сделайте find_last_of в строке для \
  3. Извлеките подстроку из этой позиции до конца, теперь вы получите имя файла
  4. Выполните find_last_of для., и подстрока с каждой стороны даст вам имя + расширение.
0 голосов
/ 02 октября 2018

Ответы Николая Меркина и Ючена Чжуна велики, но, тем не менее, из комментариев видно, что они не совсем точны

Неявное преобразование в std :: string при печати обернет имя файла в кавычки. Комментарии также не точны.

path::filename() и path::stem() возвращает новый объект пути, а path::string() возвращает ссылку на строку. Таким образом, что-то вроде std::cout << file_path.filename().string() << "\n" может вызвать проблемы с висячей ссылкой, так как строка, на которую указывает ссылка, могла быть уничтожена.

0 голосов
/ 08 апреля 2017

Для компьютеров с Linux или Unix ОС имеет две функции, связанные с путями и именами файлов.используйте man 3 basename для получения дополнительной информации об этих функциях.Преимущество использования предоставляемых системой функций заключается в том, что вам не нужно устанавливать boost или писать собственные функции.

#include <libgen.h>
       char *dirname(char *path);
       char *basename(char *path);

Пример кода со страницы руководства:

   char *dirc, *basec, *bname, *dname;
           char *path = "/etc/passwd";

           dirc = strdup(path);
           basec = strdup(path);
           dname = dirname(dirc);
           bname = basename(basec);
           printf("dirname=%s, basename=%s\n", dname, bname);

Из-за неконстантного типа аргумента функции basename (), это немного непросто, используя это внутри кода C ++.Вот простой пример из моей базы кода:

string getFileStem(const string& filePath) const {
   char* buff = new char[filePath.size()+1];
   strcpy(buff, filePath.c_str());
   string tmp = string(basename(buff));
   string::size_type i = tmp.rfind('.');
   if (i != string::npos) {
      tmp = tmp.substr(0,i);
   }
   delete[] buff;
   return tmp;
}

Использование new / delete - это не очень хороший стиль.Я мог бы поместить его в блок try / catch на случай, если что-то случится между двумя вызовами.

0 голосов
/ 16 ноября 2014

Я также использую этот фрагмент для определения соответствующего символа косой черты:

boost::filesystem::path slash("/");
    boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native();

и затем заменяю косую черту предпочитаемой косой чертой для ОС.Полезно, если вы постоянно развертываете между Linux / Windows.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...