Учитывая строку "filename.conf"
, как мне проверить часть расширения?
Мне нужно кроссплатформенное решение.
Учитывая строку "filename.conf"
, как мне проверить часть расширения?
Мне нужно кроссплатформенное решение.
Вы должны убедиться, что позаботились об именах файлов с более чем одной точкой. пример: c:\.directoryname\file.name.with.too.many.dots.ext
не будет корректно обрабатываться strchr
или find.
Мне больше всего нравится библиотека для файловых систем, которая имеет функция расширения (пути)
Это слишком простое решение?
#include <iostream>
#include <string>
int main()
{
std::string fn = "filename.conf";
if(fn.substr(fn.find_last_of(".") + 1) == "conf") {
std::cout << "Yes..." << std::endl;
} else {
std::cout << "No..." << std::endl;
}
}
return "Yes...";
вообще без проверки — подразумевается, что решение должно работать для других входных данных. В качестве еще одного встречного примера: файл с именем просто conf без расширения также вернет значение «Да...», учитывая вышеизложенное.
- person Rollie; 06.07.2013
boost::filesystem
, который прост в использовании, но обеспечивает необходимую поддержку. См. boost.org/doc/libs/1_55_0/libs. /файловая система/doc/index.htm
- person Dan Nissenbaum; 02.04.2014
Лучший способ — не писать никакого кода, который это делает, а вызывать существующие методы. В Windows PathFindExtension метод, пожалуй, самый простой.
Так почему бы вам не написать свой собственный?
Возьмем пример strrchr. Что произойдет, если вы используете этот метод для следующей строки «c:\program files\AppleGate.Net\readme»? Является ли ".Net\readme" расширением? Легко написать что-то, что работает для нескольких примеров, но может быть намного сложнее написать что-то, что работает для всех случаев.
strchr
, который находит точку, внутри вызова strchr
, который сначала находит косую черту. Таким образом, папки с точками в названии не мешают.
- person Taylor Hansen; 04.09.2016
Предполагая, что у вас есть доступ к STL:
std::string filename("filename.conf");
std::string::size_type idx;
idx = filename.rfind('.');
if(idx != std::string::npos)
{
std::string extension = filename.substr(idx+1);
}
else
{
// No extension found
}
Изменить: это кроссплатформенное решение, поскольку вы не упомянули платформу. Если вы работаете конкретно в Windows, вам нужно использовать специальные функции Windows, упомянутые другими в этой теме.
Кто-то еще упомянул повышение, но я просто хотел добавить фактический код для этого:
#include <boost/filesystem.hpp>
using std::string;
string texture = foo->GetTextureFilename();
string file_extension = boost::filesystem::extension(texture);
cout << "attempting load texture named " << texture
<< " whose extensions seems to be "
<< file_extension << endl;
// Use JPEG or PNG loader function, or report invalid extension
-lboost_filesystem
и вы получите рабочее решение.
- person jammartin; 09.03.2021
С C++17 и его std::filesystem::path::extension
(библиотека является преемником boost::filesystem) вы сделаете свое утверждение более выразительным, чем, например, используя std::string
.
#include <iostream>
#include <filesystem> // C++17
namespace fs = std::filesystem;
int main()
{
fs::path filePath = "my/path/to/myFile.conf";
if (filePath.extension() == ".conf") // Heed the dot.
{
std::cout << filePath.stem() << " is a valid type."; // Output: "myFile is a valid type."
}
else
{
std::cout << filePath.filename() << " is an invalid type."; // Output: e.g. "myFile.cfg is an invalid type"
}
}
См. также std::filesystem::path::stem, std::filesystem::path::filename.
на самом деле STL может сделать это без большого количества кода, я советую вам немного узнать о STL, потому что он позволяет вам делать некоторые причудливые вещи, во всяком случае, это то, что я использую.
std::string GetFileExtension(const std::string& FileName)
{
if(FileName.find_last_of(".") != std::string::npos)
return FileName.substr(FileName.find_last_of(".")+1);
return "";
}
это решение всегда будет возвращать расширение даже для таких строк, как «this.a.b.c.d.e.s.mp3», если оно не может найти расширение, оно вернет «».
На самом деле, самый простой способ
char* ext;
ext = strrchr(filename,'.')
Следует помнить одну вещь: если '.'
не существует в имени файла, ext будет NULL
.
Я сам наткнулся на этот вопрос сегодня, хотя у меня уже был рабочий код, я понял, что в некоторых случаях он не будет работать.
Хотя некоторые люди уже предлагали использовать некоторые внешние библиотеки, я предпочитаю писать свой собственный код в учебных целях.
Некоторые ответы включали метод, который я использовал в первую очередь (поиск последнего «.»), но я вспомнил, что в Linux скрытые файлы / папки начинаются с «.». Таким образом, если файл файла скрыт и не имеет расширения, для расширения будет использоваться все имя файла. Чтобы избежать этого, я написал этот фрагмент кода:
bool getFileExtension(const char * dir_separator, const std::string & file, std::string & ext)
{
std::size_t ext_pos = file.rfind(".");
std::size_t dir_pos = file.rfind(dir_separator);
if(ext_pos>dir_pos+1)
{
ext.append(file.begin()+ext_pos,file.end());
return true;
}
return false;
}
Я не проверял это полностью, но я думаю, что это должно работать.
Использование find/rfind std::string решает ЭТУ проблему, но если вы много работаете с путями, вам следует обратить внимание на boost::filesystem::path, так как это сделает ваш код намного чище, чем возиться с необработанными строковыми индексами/итераторами.
Я предлагаю повысить, поскольку это высококачественная, хорошо протестированная (с открытым исходным кодом и на коммерческой основе) бесплатная и полностью переносимая библиотека.
Для строк типа массива символов вы можете использовать это:
#include <ctype.h>
#include <string.h>
int main()
{
char filename[] = "apples.bmp";
char extension[] = ".jpeg";
if(compare_extension(filename, extension) == true)
{
// .....
} else {
// .....
}
return 0;
}
bool compare_extension(char *filename, char *extension)
{
/* Sanity checks */
if(filename == NULL || extension == NULL)
return false;
if(strlen(filename) == 0 || strlen(extension) == 0)
return false;
if(strchr(filename, '.') == NULL || strchr(extension, '.') == NULL)
return false;
/* Iterate backwards through respective strings and compare each char one at a time */
for(int i = 0; i < strlen(filename); i++)
{
if(tolower(filename[strlen(filename) - i - 1]) == tolower(extension[strlen(extension) - i - 1]))
{
if(i == strlen(extension) - 1)
return true;
} else
break;
}
return false;
}
Может обрабатывать пути к файлам в дополнение к именам файлов. Работает как с C, так и с C++. И кроссплатформенный.
strlen(extension)
в состоянии for
. Затем, если символы не совпадают, верните false. Внешний цикл for
возвращает true.
- person LRDPRDX; 16.02.2018
Хорошие ответы, но я вижу, что у большинства из них есть некоторые проблемы: прежде всего, я думаю, что хороший ответ должен работать для полных имен файлов, у которых есть заголовки путей, а также он должен работать для Linux или Windows или, как уже упоминалось, он должен быть кроссплатформенным. Для большинства ответов; имена файлов без расширения, но путь с именем папки, включая точку, функция не вернет правильное расширение: примеры некоторых тестов могут быть следующими:
const char filename1 = {"C:\\init.d\\doc"}; // => No extention
const char filename2 = {"..\\doc"}; //relative path name => No extention
const char filename3 = {""}; //emputy file name => No extention
const char filename4 = {"testing"}; //only single name => No extention
const char filename5 = {"tested/k.doc"}; // normal file name => doc
const char filename6 = {".."}; // parent folder => No extention
const char filename7 = {"/"}; // linux root => No extention
const char filename8 = {"/bin/test.d.config/lx.wize.str"}; // ordinary path! => str
Предложение «brian newman» не будет работать для файлов с именем1 и с именем4. и большинство других ответов, основанных на обратном поиске, не будут работать для имени файла1. Я предлагаю включить в ваш источник следующий метод: функция, возвращающая индекс первого символа расширения или длину заданной строки, если она не найдена.
size_t find_ext_idx(const char* fileName)
{
size_t len = strlen(fileName);
size_t idx = len-1;
for(size_t i = 0; *(fileName+i); i++) {
if (*(fileName+i) == '.') {
idx = i;
} else if (*(fileName + i) == '/' || *(fileName + i) == '\\') {
idx = len - 1;
}
}
return idx+1;
}
вы можете использовать приведенный выше код в своем приложении С++, как показано ниже:
std::string get_file_ext(const char* fileName)
{
return std::string(fileName).substr(find_ext_idx(fileName));
}
Последняя точка: в некоторых случаях папка задается именем файла в качестве аргумента и включает точку в имени папки, функция будет возвращать точку в конце папки, поэтому лучше сначала проверить, что данное имя является именем файла, а не именем папки.
Версия NET/CLI с использованием System::String
System::String^ GetFileExtension(System::String^ FileName)
{
int Ext=FileName->LastIndexOf('.');
if( Ext != -1 )
return FileName->Substring(Ext+1);
return "";
}
Я бы выбрал boost::filesystem::extension
a> (std::filesystem::path::extension
с C++17), но если вы не можете используйте Boost, и вам просто нужно проверить расширение, простое решение:
bool ends_with(const std::string &filename, const std::string &ext)
{
return ext.length() <= filename.length() &&
std::equal(ext.rbegin(), ext.rend(), filename.rbegin());
}
if (ends_with(filename, ".conf"))
{ /* ... */ }
_splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w
Это только для Windows (платформенный SDK)
Это решение, которое я придумал. Затем я заметил, что это похоже на то, что опубликовал @serengeor.
Он работает с std::string
и find_last_of
, но основная идея также будет работать, если ее изменить для использования массивов char
и strrchr
. Он обрабатывает скрытые файлы и дополнительные точки, представляющие текущий каталог. Он не зависит от платформы.
string PathGetExtension( string const & path )
{
string ext;
// Find the last dot, if any.
size_t dotIdx = path.find_last_of( "." );
if ( dotIdx != string::npos )
{
// Find the last directory separator, if any.
size_t dirSepIdx = path.find_last_of( "/\\" );
// If the dot is at the beginning of the file name, do not treat it as a file extension.
// e.g., a hidden file: ".alpha".
// This test also incidentally avoids a dot that is really a current directory indicator.
// e.g.: "alpha/./bravo"
if ( dotIdx > dirSepIdx + 1 )
{
ext = path.substr( dotIdx );
}
}
return ext;
}
Модульный тест:
int TestPathGetExtension( void )
{
int errCount = 0;
string tests[][2] =
{
{ "/alpha/bravo.txt", ".txt" },
{ "/alpha/.bravo", "" },
{ ".alpha", "" },
{ "./alpha.txt", ".txt" },
{ "alpha/./bravo", "" },
{ "alpha/./bravo.txt", ".txt" },
{ "./alpha", "" },
{ "c:\\alpha\\bravo.net\\charlie.txt", ".txt" },
};
int n = sizeof( tests ) / sizeof( tests[0] );
for ( int i = 0; i < n; ++i )
{
string ext = PathGetExtension( tests[i][0] );
if ( ext != tests[i][1] )
{
++errCount;
}
}
return errCount;
}
Я использую эти две функции для получения расширения и имени файла без расширения:
std::string fileExtension(std::string file){
std::size_t found = file.find_last_of(".");
return file.substr(found+1);
}
std::string fileNameWithoutExtension(std::string file){
std::size_t found = file.find_last_of(".");
return file.substr(0,found);
}
И эти regex
подходят для некоторых дополнительных требований:
std::string fileExtension(std::string file){
std::regex re(".*[^\\.]+\\.([^\\.]+$)");
std::smatch result;
if(std::regex_match(file,result,re))return result[1];
else return "";
}
std::string fileNameWithoutExtension(std::string file){
std::regex re("(.*[^\\.]+)\\.[^\\.]+$");
std::smatch result;
if(std::regex_match(file,result,re))return result[1];
else return file;
}
Дополнительные требования, которым отвечает метод regex:
.config
или что-то подобное, расширение будет пустой строкой, а имя файла без расширения будет .config
.ИЗМЕНИТЬ:
Дополнительные требования также могут быть выполнены следующим образом:
std::string fileExtension(const std::string& file){
std::string::size_type pos=file.find_last_of('.');
if(pos!=std::string::npos&&pos!=0)return file.substr(pos+1);
else return "";
}
std::string fileNameWithoutExtension(const std::string& file){
std::string::size_type pos=file.find_last_of('.');
if(pos!=std::string::npos&&pos!=0)return file.substr(0,pos);
else return file;
}
Примечание.
Передайте только имена файлов (не путь) в вышеуказанных функциях.
Попробуйте использовать strstr.
char* lastSlash;
lastSlash = strstr(filename, ".");
Или вы можете использовать это:
char *ExtractFileExt(char *FileName)
{
std::string s = FileName;
int Len = s.length();
while(TRUE)
{
if(FileName[Len] != '.')
Len--;
else
{
char *Ext = new char[s.length()-Len+1];
for(int a=0; a<s.length()-Len; a++)
Ext[a] = FileName[s.length()-(s.length()-Len)+a];
Ext[s.length()-Len] = '\0';
return Ext;
}
}
}
Этот код кроссплатформенный
Если вы используете библиотеку Qt, вы можете попробовать QFileInfo суффикс()
Вот функция, которая принимает путь/имя файла в виде строки и возвращает расширение в виде строки. Это все стандартный С++, и он должен работать кросс-платформенно для большинства платформ.
В отличие от нескольких других ответов здесь, он обрабатывает нечетные случаи, которые обрабатывает Windows PathFindExtension, на основе документации PathFindExtensions.
wstring get_file_extension( wstring filename )
{
size_t last_dot_offset = filename.rfind(L'.');
// This assumes your directory separators are either \ or /
size_t last_dirsep_offset = max( filename.rfind(L'\\'), filename.rfind(L'/') );
// no dot = no extension
if( last_dot_offset == wstring::npos )
return L"";
// directory separator after last dot = extension of directory, not file.
// for example, given C:\temp.old\file_that_has_no_extension we should return "" not "old"
if( (last_dirsep_offset != wstring::npos) && (last_dirsep_offset > last_dot_offset) )
return L"";
return filename.substr( last_dot_offset + 1 );
}
max( filename.rfind(L'\\'), filename.rfind(L'/') )
будет сравнивать два значения без знака, одно из них может быть npos
, которое является максимально возможным целым числом без знака. Таким образом, может показаться, что папки нет, даже если она есть!
- person Andrii Kovalevskyi; 30.04.2015
Вы можете использовать strrchr(), чтобы найти последнее вхождение .(точка) и получить файлы расширений на основе .(точка). Например, проверьте приведенный ниже код.
#include<stdio.h>
void GetFileExtension(const char* file_name) {
int ext = '.';
const char* extension = NULL;
extension = strrchr(file_name, ext);
if(extension == NULL){
printf("Invalid extension encountered\n");
return;
}
printf("File extension is %s\n", extension);
}
int main()
{
const char* file_name = "c:\\.directoryname\\file.name.with.too.many.dots.ext";
GetFileExtension(file_name);
return 0;
}
Если вы рассматриваете расширение как последнюю точку и возможные символы после нее, но только если они не содержат символа разделителя каталогов, следующая функция возвращает начальный индекс расширения или -1, если расширение не найдено. Когда у вас есть это, вы можете делать все, что хотите, например, удалить расширение, изменить его, проверить и т. Д.
long get_extension_index(string path, char dir_separator = '/') {
// Look from the end for the first '.',
// but give up if finding a dir separator char first
for(long i = path.length() - 1; i >= 0; --i) {
if(path[i] == '.') {
return i;
}
if(path[i] == dir_separator) {
return -1;
}
}
return -1;
}
Я использовал функцию PathFindExtension(), чтобы узнать, является ли это действительным файлом tif или нет.
#include <Shlwapi.h>
bool A2iAWrapperUtility::isValidImageFile(string imageFile)
{
char * pStrExtension = ::PathFindExtension(imageFile.c_str());
if (pStrExtension != NULL && strcmp(pStrExtension, ".tif") == 0)
{
return true;
}
return false;
}
Если вы используете библиотеки Poco, вы можете сделать следующее:
#include <Poco/Path.h>
...
std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"