C++ Get File Extension Without Providing Extension In The Path - c++

I have a bunch of images called Apple-1, ..., Apple-n but I don't know if Apple-x is a .jpeg or .png and I want to determine that without knowing that it's a .jpeg or something else.
What I know is how the images are labeled and I want to get their extensions into a string (not all in one string, I would check for every image).
I appreciate any ideas :)
(There was a similar question asked here, but that's for C#: Get extension of file without providing extension in the path)

You can easily do that with boost::filesystem:
Example
boost::filesystem::path folder(boost::filesystem::current_path());
for (boost::filesystem::directory_iterator it(folder), end;
it != end; ++it)
{
auto ext = it->path().extension();
if (ext == ".jpeg")
{
std::cout << "is jpeg" << std::endl;
}
}

The boost filesystem library offers an excellent set of functions for this and related path issues" see here

Related

C++ directory search

So I'm trying to write a little C++ program to check whether or not a directory exists on a Windows platform (I am aware that other languages are more suited for this type of use, but I want to do it in c++).
This is what I have so far (it compiles):
std::string DirectorySelector::SpecifyDirectory(void)
{
std::cout << "Enter directory for file renaming: ";
std::cin >> directory;
if (ValidateDirectory(directory) == 1) { SpecifyDirectory(); }
else { return directory; }
}
int DirectorySelector::ValidateDirectory(std::string directory)
{
error = "Error 01: Directory not found.";
std::ifstream fin (directory);
if (!fin)
{
std::cerr << error << "\n\n";
fin.close();
return 1;
}
else
{
fin.close();
return 2;
}
}
So obviously I'm currently asking for the user to input their desired directory as a string, not sure if this is a wise choice?
I have done a little research into whether Windows folders (directories) have an extension, but it appears not.
I assume I am missing something obvious, such as a predefined C++ keyword to use somewhere?
If any answers could be fully explained as to what is going on that would be fantastic, as I don't like to use stuff which I don't understand.
Plus any tips to do with coding standards that I may not be adhering to would obviously be greatly appreciated.
Thanks in advance.
If you want to use DIRENT (unix method) in windows then see here, advantage is cross platform (dirent is pretty much everywhere except windows):
http://www.softagalleria.net/dirent.php
If you want to use the Windows API for this:
How to check if directory exist using C++ and winAPI
For a portable (across many platforms) file-management system you could use boost::filesystem
The documentation may look a bit complex for a relative beginner but they probably give you examples that will enable you to get going on what you want, and if you get stuck you can always come back here and ask specifics.
Your existing code is incorrect in its use of ifstream which is used to open a file for read-only. You cannot use this to open a directory (to list its contents or see if it exists).

How to get file extension correctly in C++? Windows Platform

There are many posts and answers to this question on this site, however no one can offer something worth.
One of the most popular solutions is to get file extension from a string.
For example, if I had a string "myFile.dot". The result of getting extension would be ".dot", however, this actually can also be a folder, not a file, can't it?
How would the function recognize that?
Another case, if I had a file with the extension ".jfhdj" for example, which actually doesn't exist, how should I handle it?
Concerning the boost::filesystem file extension. As far as I google it, it can get one specific file extension, but not any. I mean this function
boost::filesystem::path folder(boost::filesystem::current_path());
for (boost::filesystem::directory_iterator it(folder), end;
it != end; ++it)
{
auto ext = it->path().extension();
if (ext == ".jpeg")
{
std::cout << "is jpeg" << std::endl;
}
}
Could you tell me please if struct stat can give me the file extension as one of the attributes, or is there any WINAPI function that can get the file extension not from a string. Or what would you personally advice? Hope to hear from you soon. Thank you.

Finding the file path of all files in a folder

I'm trying to convert a bunch of images to textures using SDL. So far, I know its possible to do everything manually:
//Load front alpha texture
if (!gModulatedTexture.loadFromFile("14_animated_sprites_and_vsync/text2.png"))
{
printf("Failed to load front texture!\n");
success = false;
}
else
.....
However, I have quite a few images I want to load so what I'm looking for is a way to automate the process. I want to put all my images into a single folder, and then do something like this:
i=0
while (there are still images to load) {
textureBank[i] = current image
i++
}
I wast thinking there might be some easy way to just read in the file path of all the files in a directory, but I haven't been able to find a way to do that.
Any suggestions?
You don't need to use any 3rd-party library like boost, just call the following function (for Windows OS). After this, you will get all file paths within given folder in vector<string>.
#include <Windows.h>
// folder must end with "/", e.g. "D:/images/"
vector<string> get_all_files_full_path_within_folder(string folder)
{
vector<string> names;
char search_path[200];
sprintf(search_path, "%s*.*", folder.c_str());
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path, &fd);
if(hFind != INVALID_HANDLE_VALUE)
{
do
{
// read all (real) files in current folder, delete '!' read other 2 default folder . and ..
if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
names.push_back(folder+fd.cFileName);
}
}while(::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
Since you are using SDL, I’ll assume you want to be cross-platform. The boost::filesystem library can do this.
Take a look at their directory iteration example.
Although it’s part of a 3rd-party library, boost::filesystem is proposed for inclusion in a future C++ standard, TR2, so it’s worth the effort to learn. It should eventually be the standard C++ way to work with files and directories.

Check whether a string is a valid filename with Qt

Is there a way with Qt 4.6 to check if a given QString is a valid filename (or directory name) on the current operating system ? I want to check for the name to be valid, not for the file to exist.
Examples:
// Some valid names
test
under_score
.dotted-name
// Some specific names
colon:name // valid under UNIX OSes, but not on Windows
what? // valid under UNIX OSes, but still not on Windows
How would I achieve this ? Is there some Qt built-in function ?
I'd like to avoid creating an empty file, but if there is no other reliable way, I would still like to see how to do it in a "clean" way.
Many thanks.
This is the answer I got from Silje Johansen - Support Engineer - Trolltech ASA (in March 2008 though)
However. the complexity of including locale settings and finding
a unified way to query the filesystems on Linux/Unix about their
functionality is close to impossible.
However, to my knowledge, all applications I know of ignore this
problem.
(read: they aren't going to implement it)
Boost doesn't solve the problem either, they give only some vague notion of the maximum length of paths, especially if you want to be cross platform. As far as I know many have tried and failed to crack this problem (at least in theory, in practice it is most definitely possible to write a program that creates valid filenames in most cases.
If you want to implement this yourself, it might be worth considering a few not immediately obvious things such as:
Complications with invalid characters
The difference between file system limitations and OS and software limitations. Windows Explorer, which I consider part of the Windows OS does not fully support NTFS for example. Files containing ':' and '?', etc... can happily reside on an ntfs partition, but Explorer just chokes on them. Other than that, you can play safe and use the recommendations from Boost Filesystem.
Complications with path length
The second problem not fully tackled by the boost page is length of the full path. Probably the only thing that is certain at this moment is that no OS/filesystem combination supports indefinite path lengths. However, statements like "Windows maximum paths are limited to 260 chars" are wrong. The unicode API from Windows does allow you to create paths up to 32,767 utf-16 characters long. I haven't checked, but I imagine Explorer choking equally devoted, which would make this feature utterly useless for software having any users other than yourself (on the other hand you might prefer not to have your software choke in chorus).
There exists an old variable that goes by the name of PATH_MAX, which sounds promising, but the problem is that PATH_MAX simply isn't.
To end with a constructive note, here are some ideas on possible ways to code a solution.
Use defines to make OS specific sections. (Qt can help you with this)
Use the advice given on the boost page and OS and filesystem documentation to decide on your illegal characters
For path length the only workable idea that springs to my mind is a binary tree trial an error approach using the system call's error handling to check on a valid path length. This is quite aloof, but might be the only possibility of getting accurate results on a variety of systems.
Get good at elegant error handling.
Hope this has given some insights.
Based on User7116's answer here:
How do I check if a given string is a legal/valid file name under Windows?
I quit being lazy - looking for elegant solutions, and just coded it. I got:
bool isLegalFilePath(QString path)
{
if (!path.length())
return false;
// Anything following the raw filename prefix should be legal.
if (path.left(4)=="\\\\?\\")
return true;
// Windows filenames are not case sensitive.
path = path.toUpper();
// Trim the drive letter off
if (path[1]==':' && (path[0]>='A' && path[0]<='Z'))
path = path.right(path.length()-2);
QString illegal="<>:\"|?*";
foreach (const QChar& c, path)
{
// Check for control characters
if (c.toLatin1() >= 0 && c.toLatin1() < 32)
return false;
// Check for illegal characters
if (illegal.contains(c))
return false;
}
// Check for device names in filenames
static QStringList devices;
if (!devices.count())
devices << "CON" << "PRN" << "AUX" << "NUL" << "COM0" << "COM1" << "COM2"
<< "COM3" << "COM4" << "COM5" << "COM6" << "COM7" << "COM8" << "COM9" << "LPT0"
<< "LPT1" << "LPT2" << "LPT3" << "LPT4" << "LPT5" << "LPT6" << "LPT7" << "LPT8"
<< "LPT9";
const QFileInfo fi(path);
const QString basename = fi.baseName();
foreach (const QString& d, devices)
if (basename == d)
// Note: Names with ':' other than with a drive letter have already been rejected.
return false;
// Check for trailing periods or spaces
if (path.right(1)=="." || path.right(1)==" ")
return false;
// Check for pathnames that are too long (disregarding raw pathnames)
if (path.length()>260)
return false;
// Exclude raw device names
if (path.left(4)=="\\\\.\\")
return false;
// Since we are checking for a filename, it mustn't be a directory
if (path.right(1)=="\\")
return false;
return true;
}
Features:
Probably faster than using regexes
Checks for illegal characters and excludes device names (note that '' is not illegal, since it can be in path names)
Allows drive letters
Allows full path names
Allows network path names
Allows anything after \\?\ (raw file names)
Disallows anything starting with \\.\ (raw device names)
Disallows names ending in "\" (i.e. directory names)
Disallows names longer than 260 characters not starting with \\?\
Disallows trailing spaces and periods
Note that it does not check the length of filenames starting with \\?, since that is not a hard and fast rule. Also note, as pointed out here, names containing multiple backslashes and forward slashes are NOT rejected by the win32 API.
I don't think that Qt has a built-in function, but if Boost is an option, you can use Boost.Filesystem's name_check functions.
If Boost isn't an option, its page on name_check functions is still a good overview of what to check for on various platforms.
Difficult to do reliably on windows (some odd things such as a file named "com" still being invalid) and do you want to handle unicode, or subst tricks to allow a >260 char filename.
There is already a good answer here How do I check if a given string is a legal / valid file name under Windows?
see example (from Digia Qt Creator sources) in: https://qt.gitorious.org/qt-creator/qt-creator/source/4df7656394bc63088f67a0bae8733f400671d1b6:src/libs/utils/filenamevalidatinglineedit.cpp
I'd just create a simple function to validate the filename for the platform, which just searches through the string for any invalid characters. Don't think there's a built-in function in Qt. You could use #ifdefs inside the function to determine what platform you're on. Clean enough I'd say.

How to know and load all images in a specific folder?

I have an application (C++ Builder 6.0) that needs to know the total of images there are in a specific folder, and then I have to load them: in an ImageList or in a ComboBoxEx... or any other control...
How can I do that?
I know how to load an image in a control, or to save in a TList, or in an ImageList... but How to know how many files files there are in the directory, and how to load every image in it??
I am Sorry about my English.
I did something like this yesterday with C++ using the boost::filesystem library. However, if you are not using boost already, I would strongly recommend you just use the windows libraries instead. This was my code though in case you're interested:
#include <algorithm>
#include <boost/filesystem.hpp>
#include <set>
namespace fs = boost::filesystem;
typedef std::vector<fs::path> PathVector;
std::auto_ptr<PathVector> ImagesInFolder(const fs::path& folderPath) {
std::set<std::string> targetExtensions;
targetExtensions.insert(".JPG");
targetExtensions.insert(".BMP");
targetExtensions.insert(".GIF");
targetExtensions.insert(".PNG");
std::auto_ptr<PathVector> paths(new PathVector());
fs::directory_iterator end;
for(fs::directory_iterator iter(folderPath); iter != end; ++iter) {
if(!fs::is_regular_file(iter->status())) { continue; }
std::string extension = iter->path().extension();
std::transform(extension.begin(), extension.end(), extension.begin(), ::toupper);
if(targetExtensions.find(extension) == targetExtensions.end()) { continue; }
paths->push_back(iter->path());
}
return paths;
}
This doesn't answer the part of your question about how to actually put the paths into a listbox though.
Use the Win32 functions FindFirstFile and FindNextFile ...?
There's no practical way to identify every image in an arbitrary folder. Almost anything you can't identify as something else, could be some sort of image. Then again, using steganography, even something you can identify as something else still might be (or contain) at least part of an image as well.
Realistically, you want to pick out a set of formats you want to support, and write code that knows about them. For quite a few purposes, a half dozen formats or so is quite adequate, though the exact half dozen you pick will vary by the type of application -- only a few programs have any use for both bitmapped and vector graphics, for one example.
Once you've decided what you want, DlgDirList is probably the easiest way to list some files. If that isn't flexible enough for your purposes, the next obvious choice is FindFirstFile, FindNextFile, and FindClose.
To get a list of all files in a folder, have a look at the FindFirst and FindNext functions in SysUtils.
Here is an example function which shows how to get a list of files.
void __fastcall TForm1::GetDirList(TStrings *List, const AnsiString SearchStr)
{
TSearchRec SRec;
AnsiString TempFName;
List->Clear();
// start search
if (FindFirst(SearchStr, faAnyFile, SRec) == 0)
{
do
{
if ((SRec.Attr & faDirectory) != faDirectory) // exclude directories
{
List->Add(SRec.Name);
} // end if
}
while (FindNext(SRec) == 0);
FindClose(SRec);
} // end if
}
Examples:
// get list of all files in directory
GetDirList(MyStringList, "C:\images*.*");
// get list of all .bmp files in directory
GetDirList(MyStringList, "C:\images\*.bmp");
If you can upgrade to newer version of C++Builder, have a look at TMS AdvSmoothImageListBox, from TMS Software.
The TMS Smooth Controls are available free for C++Builder 2010 users on the from Embarcadero website.