C++ iterating through files and directories - c++

I'm working on a C++ program that will automatically backup my work to my FTP server. So far I am able to upload a single file, by specifying a file name using this
CString strFilePath = szFile ;
int iPos = strFilePath.ReverseFind('\\');
CString strFileName = strFilePath.Right((strFilePath.GetLength()- iPos-1) );
CString strDirPath = m_szFolderDroppedIn ;
strDirPath = strDirPath.Mid(0,strDirPath.GetLength() - 1);
int iPost = strDirPath.ReverseFind('\\');
CString strDirName = strDirPath.Right((strDirPath.GetLength()- iPost -1) );
bool curdir = ftpclient.SetServerDirectory((char*)strDirName.GetBuffer(strDirName.GetLength()));
//Upload to Server
int uploadret = ftpclient.PutFile(szFile,(char*)strFileName.GetBuffer(strFileName.GetLength()),0,true,dwLastError);
m_lsDroppedFiles.RemoveAll();
break;
}
Now I want to be able to iterate through a directory (Which contains subdirectories) and recursively call. I'm having a problem getting a hold of the files in the directory.
Any help or code snippet...

Since you are using MFC, you can use the CFileFind class. Example code is given in MSDN. Alternatively, you can use boost.filesystem for the same.

#Swapnil: If you use boost::filesystem, there is a recursive_directory_iterator

Related

Add files to the existing archive in XZip, C++, Windows

I am creating a windows service that periodically copies the contents of a folder to an archive. I've searched for archiving libraries and found suggestions to use XZip.
Now I can create a new archive using code like this:
HZIP arch = CreateZip((void*)Archive.c_str(), 0, ZIP_FILENAME);
if (arch == nullptr)
return addLogMessage("Unable to open archive.");
for (const auto& file : std::filesystem::directory_iterator(Directory)) {
const std::wstring filePath = file.path().wstring();
const std::wstring nameInArchive = file.path().filename().wstring();
if (ZipAdd(arch, (TCHAR*)nameInArchive.c_str(), (TCHAR*)filePath.c_str(), 0, ZIP_FILENAME) != ZR_OK) {
std::string what = "Error: Adding '" + std::string(filePath.begin(), filePath.end()) + "' to the archive.";
addLogMessage(what.c_str());
}
}
CloseZip(arch);
I also want to add files to an existing archive. When I run the code below, I get a ZR_ZMODE error from the ZipAdd function, which means tried to mix create / open zip archive:
if (std::filesystem::exists(Archive)) {
HZIP arch = OpenZip((void*)Archive.c_str(), 0, ZIP_FILENAME);
if (arch == nullptr)
return addLogMessage("Unable to re-open existing archive.");
for (const auto& file : std::filesystem::directory_iterator(Directory)) {
const std::wstring filePath = file.path().wstring();
const std::wstring nameInArchive = file.path().filename().wstring();
if (ZipAdd(arch, (TCHAR*)nameInArchive.c_str(), (TCHAR*)filePath.c_str(), 0, ZIP_FILENAME) != ZR_OK) {
std::string what = "Error: Adding '" + std::string(filePath.begin(), filePath.end()) + "' to the archive.";
addLogMessage(what.c_str());
}
}
CloseZip(arch);
}
I assume that in XZip library, I'm not able to add files to the existing archive. Is it true?
EDIT: I've solved the problem with different library, libzip. Now I can add new files to the old archive, and everything works fine. I've posted source code and compiling/linking instruction here.
I am still interested, if there is an option for adding files to the existing archive in XZip library, so I will not close the question for now.

Accessing files in resources folder in mac osx app bundle

I would like to access files which are inside Resources in app bundle. Unfortunately i cannot use QT resorces, as i'm using CascadeClassifier from opencv. My current paths are
const std::string FACE_CLASIFIER_PATH = "/Resources/haarcascade_frontalface_default.xml";
const std::string EYES_CLASIFIER_PATH = "/Resources/haarcascade_mcs_eyepair_big.xml";
I also tried
const std::string FACE_CLASIFIER_PATH = "../Resources/haarcascade_frontalface_default.xml";
const std::string EYES_CLASIFIER_PATH = "../Resources/haarcascade_mcs_eyepair_big.xml";
But nether of them work. As for config both files are present inside MyApp.app/Contents/Resources, i include them using qmake
mac {
APP_XML_FILES.files = ../haarcascade_frontalface_default.xml ../haarcascade_mcs_eyepair_big.xml
APP_XML_FILES.path = Contents/Resources
QMAKE_BUNDLE_DATA += APP_XML_FILES
}
I would appreciate any help with this issue
You don't say what you want to do with the files, though that could be due to my lack of knowledge of opencv. However you can use the Core Foundation classes to get paths to files in the resources folder: -
CFURLRef appUrlRef;
appUrlRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("somefile"), NULL, NULL);
// do something with the file
//...
// Ensure you release the reference
CFRelease(appUrlRef);
With a CFURLRef, you can use Apple's documentation to get what you need from it.
For example, if you want a file path: -
CFStringRef filePathRef = CFURLCopyPath(appUrlRef);
// Always release items retrieved with a function that has "create or "copy" in its name
CFRelease(filePathRef);
From the file path, we can get a char* to the path: -
const char* filePath = CFStringGetCStringPtr(filePathRef, kCFStringEncodingUTF8);
So, putting it all together, if you want to get a char* path to haarcascade_mcs_eyepair_big.xml: -
CFURLRef appUrlRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("haarcascade_mcs_eyepair_big.xml"), NULL, NULL);
CFStringRef filePathRef = CFURLCopyPath(appUrlRef);
const char* filePath = CFStringGetCStringPtr(filePathRef, kCFStringEncodingUTF8);
// Release references
CFRelease(filePathRef);
CFRelease(appUrlRef);

filesystem directory_iterator not returning full file path

EDIT: I'm using std::tr2::sys not boost's filesytem
I'm working on a simple app that scans directories on the computer and returns statistics about those files. There are two ways that scan can be called: recursively and non-recursively. A path is passed into the scan method along with a flag for whether or not the scan should be done recursively. Given the path folder the two implementations look something like this:
directory_iterator start( folder ), end;
for( ; start != end; ++start ) {
//Some code in here
// get the path like this:
auto path = start->path();
}
or
recursive_directory_iterator start( folder ), end;
for( ; start != end; ++start ) {
//Some code in here
// get the path like this:
auto path = start->path();
}
The problem I'm encountering is that in the block that uses the regular directory_iterator when I try and grab the path it will return only the file name ie. "myTextFile.txt" where as getting it from the recursive_directory_iterator returns the full path to the file on the system. In each case the value of folder is the same (a full file path as well). Is there a reason the front part of the path is getting chopped off or is there some way I can get the full file path from just the abbreviated one that I'm getting back from directory_iterator?
For full path you need to use start->path().directory_string()
directory_iterator end;
for (directory_iterator start(p);
start != end;
++start)
{
if (is_directory(start->status()))
{
//A directory
}
if (is_regular_file(start->status()))
{
std::cout << start->path().directory_string()<< "\n";
}
}
Play around with following based on your need, refer boost docs for more details, however names their suggest all.
start->path().branch_path();
start->path().directory_string();
start->path().file_string();
start->path().root_path();
start->path().parent_path();
start->path().string();
start->path().basename();
start->path().filename();
start->path().root_name();
start->path().relative_path();
Use the complete function:
auto full_path = std::tr2::sys::complete(path, folder);
Another simple way to do it would be be to simply append the filename to the path (tested on MSVC2012 with the <filesystem> in the std::tr2::sys namespace):
for (; start != end; ++start) {
auto path = start->path();
auto full_path = folder / path;
}

Search a file in a directory

I work in a project and I need to know if a file is unique in a directory or not.
So how can I find if a file exists in a directory or not?
I have the file name without extension and the path of the directory.
There's no ready-made function for this I think, but you can use something like this:
static bool fileExists( const char *path )
{
const DWORD attr = ::GetFileAttributesA( path );
return attr != INVALID_FILE_ATTRIBUTES &&
( ( attr & FILE_ATTRIBUTE_ARCHIVE ) || ( attr & FILE_ATTRIBUTE_NORMAL ) );
}
This verifies that it's a "normal" file. You might want to add/remove flag checks if you want to deal with hidden files, too.
I prefer to do this on a C++ way, but you mentioned a Visual-C++ tag, so there's a way to do it on Visual-C++.NET:
using <mscorlib.dll>
using namespace System;
using namespace System::IO;
bool search(String folderPath, String fileName) {
String* files[] = Directory::GetFiles(folderPath, fileName+".*"); //search the file with the name fileName with any extension (remember, * is a wildcard)
if(files->getLength() > 0)
return true; //there are one or more files with this name in this folder
else
return false; //there arent any file with this name in this folder
}

Using taglib in a Qt application

I'd like to get the length of a media file in a qt application i'm building and so i decided to use taglib. This is the methos that is meant to read the length
void loadMetaData(QString file) {
QByteArray fileName = QFile::encodeName( file );
const char * encodedName = fileName.constData();
TagLib::FileRef fileref = TagLib::FileRef( encodedName );
if (fileref.isNull())
{
qDebug() << "Null";
}
else
{
qDebug() << "Not Null";
}
}
Problem is fileref is always null for some reason and i can't figure out why......
Use the getter audioProperties() on your FileRef object. The returned pointer contains the length of the file in seconds.
TagLib# is able to work with some Theora files. I used it in a project but found it wouldn't work with many Theora videos (I don't think any converted using libtheora 1.1 worked).
TagLib.File file = TagLib.File.Create(#"c:\video.ogv");
string height = file.Properties.VideoHeight;
This is for the .NET, not C++ though.