У мене є список файлів, що зберігаються в a .log
в такому синтаксисі:
c:\foto\foto2003\shadow.gif
D:\etc\mom.jpg
Я хочу витягти ім'я та розширення з цих файлів. Чи можете ви навести приклад простого способу зробити це?
Відповіді:
Щоб витягти ім'я файлу без розширення, використовуйте 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
std::experimental::filesystem
відп std::filesystem
. Дивіться публікацію Ючен Чжун нижче.
Для 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
std::filesystem::path
на std::string
, щоб мати можливість використовувати std::cout
. en.cppreference.com/w/cpp/filesystem/path/filename. Але якщо ви думаєте інакше, сміливо коментуйте або редагуйте публікацію ще раз.
std::cout
можна покладатися на неявне перетворення. Однак, оскільки коментарі після std::cout
сказати file.ext та файл, або .string()
їх потрібно додати до коментарів, або вони повинні бути "file.ext" та "file". З Visual C ++ насправді немає ніякої різниці (навіть без string()
виводу без лапок), але з gcc 6.1 результат виводиться із лапок, якщо .string()
його не вказано. Див. Coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
Якщо ви хочете безпечний спосіб (тобто переносний між платформами, а не розміщення припущень на шляху), я рекомендую скористатися цим boost::filesystem
.
Це виглядало б якось так:
boost::filesystem::path my_path( filename );
Тоді ви можете витягти різні дані з цього шляху. Ось документація об'єкта path.
BTW: Також пам'ятайте, що для використання шляху типу
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
. Отримавши ім’я файлу в a 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 = "";
}
}
Не код, але ось ідея:
std::string
із вхідного потоку ( std::ifstream
), кожен зчитуваний екземпляр буде повним шляхомfind_last_of
на рядку для\
find_last_of
for .
, і підрядок з будь-якої сторони дасть вам ім'я + розширення./
також. І я навіть не знаю, чи існує більше застережень у специфікаціях шляхів, тому моє мислення просте - якщо є хороша бібліотека, яка робить те, що я хочу, я повинен використовувати її, бо це, можливо, досягне моєї мети краще, ніж я можу. ;)
boost::insects::disperser<T>
загального шаблону? :)
Я також використовую цей фрагмент для визначення відповідного косого символу:
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);
Приклад коду зі сторінки користувача:
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);
Через тип аргументу non-const функції 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, якщо щось трапиться між двома дзвінками.
Спробуйте наступний трюк, щоб витягти ім'я файлу із шляху без розширення в c ++ без зовнішніх бібліотек у c ++:
#include <iostream>
#include <string>
using std::string;
string getFileName(const string& s) {
char sep = '/';
#ifdef _WIN32
sep = '\\';
#endif
size_t i = s.rfind(sep, s.length());
if (i != string::npos)
{
string filename = s.substr(i+1, s.length() - i);
size_t lastindex = filename.find_last_of(".");
string rawname = filename.substr(0, lastindex);
return(rawname);
}
return("");
}
int main(int argc, char** argv) {
string path = "/home/aymen/hello_world.cpp";
string ss = getFileName(path);
std::cout << "The file name is \"" << ss << "\"\n";
}
Відповіді Миколая Меркіна та Ючен Чжун є чудовими, але з коментарів видно, що вони не є повністю точними.
Неявне перетворення в std :: string під час друку оберне ім'я файлу в лапки. Коментарі також не є точними.
path::filename()
і path::stem()
повертає новий об'єкт шляху і path::string()
повертає посилання на рядок. Таким чином, щось подібне std::cout << file_path.filename().string() << "\n"
може спричинити проблеми із звисаючим посиланням, оскільки рядок, на який посилає посилання, може бути знищений.