Как я могу извлечь имя файла и расширение из пути в C++



у меня есть список файлов, хранящийся в .log в следующий синтаксис:



c:fotofoto2003shadow.gif
D:etcmom.jpg


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

2323   8  

8 ответов:

чтобы извлечь имя файла без расширения, используйте 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

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

это выглядело бы как-то так:

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

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


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

c:\foto\foto2003\shadow.gif

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

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

или использовать / вместо:

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

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

вы должны будете прочитать ваши имена файлов из файла в 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  = "";
    }
}

на 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 by p.filename().string() если это то, что вам нужно, например:

filename and extension: file.ext

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

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

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

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

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

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

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

пример кода из man-страницы:

   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 блок на случай, если что-то произошло между двумя вызовами.

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

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

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

Comments

    Ничего не найдено.