2

I am having a program which reads images from a folder. I am using a for to access all the index of the files and store them into a vector:

    for(int i=0; i<labels.size(); i++){

    ostringstream stringStream;
    stringStream << setfill ('0') << setw (4) << i;
    num2string = stringStream.str();

    string img = "C:\\opencvAssets/detected/BioID_"+num2string+".pgm";
    //cout<< img <<" \n";
    images.push_back(imread(img, CV_LOAD_IMAGE_GRAYSCALE));  //labels.push_back(i);
}

I am having some troubles, since some of the files delibrately is missing from the folder. Thus, for approach is prohibitive. How can I read all the files and store them into a vector??

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
Jose Ramon
  • 5,572
  • 25
  • 76
  • 152
  • There is no way to get the contents of a directory using the standard library. However I suspect boost may provide an abstraction for that. – stefan Dec 12 '13 at 13:15
  • You want to check whether a file with a given string name exists or not, right? Check this out http://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c or maybe this http://stackoverflow.com/questions/18320486/how-to-check-if-file-exists-in-c-in-a-portable-way – Ranveer Dec 12 '13 at 13:16
  • 2
    If you have access to boost, use the directory iterator from the filesystem library. – 111111 Dec 12 '13 at 13:19
  • 1
    I had the same problem, and solved it using dirent and fnmatch. – G B Dec 12 '13 at 13:23

5 Answers5

4

First you need to scan directory and get files:

You can use FindFirstFile and FindNextFile

bool find_files(){
  WIN32_FIND_DATA FindFileData;
  string img = "C:\\opencvAssets/detected/BioID_*.pgm";
  HANDLE hFind = FindFirstFile(img.c_str(), &FindFileData);
  if(hFind == INVALID_HANDLE_VALUE){
    return false;
  } 
  else do{
    cout<<FindFileData.cFileName<<endl;
  } while (FindNextFile(hFind, &FindFileData));
  FindClose(hFind);
  return true;
}

EDIT:

For Linux: you can check here how to iterate directory, but the best way is to use fork and execv to run a find command and get output with pipes. like this

EDIT2 From terminal you can find all files like this:

find path/to/dir -name 'BioID_*.pgm'

So you can run it with redirect to file or use fork and execv. If you wan't a simple solution use it from system with redirect to a file, and open the file with all the founded file names.

Community
  • 1
  • 1
SHR
  • 7,940
  • 9
  • 38
  • 57
  • This is only going to work in Windows. If you don't need it on other platforms, it's ok. – G B Dec 12 '13 at 13:25
  • yes but he gave a windows path as constant so I can't believe he want other OS. – SHR Dec 12 '13 at 13:26
  • I am actually want it both win and linux!! The paths is just an example!! – Jose Ramon Dec 12 '13 at 13:29
  • I am trying to use the approach in http://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c, using exists function.. bool exists(const std::string& name). I am a little bit confused on how call exists function. What it has to be the parameter of the function?? – Jose Ramon Dec 12 '13 at 13:32
  • see my edit for solutions in Linux/UNIX. the exists should get a path to file. it is not good since you can't scan millions possibilities. opendir is better option but you get unfiltered file names. – SHR Dec 12 '13 at 13:42
  • 1
    I wouldn't use fork() for that. – G B Dec 12 '13 at 13:48
  • He can run a system command and redirect to file. then open the file and read lines, it not so nice programming so I find it hard to believe that if he'll do so he`ll get the programmer of the year award... – SHR Dec 12 '13 at 13:57
3

a patch:

if (Cv::mat m = imread(img, CV_LOAD_IMAGE_GRAYSCALE)) images.push_back(m); 

but for serious tasks use boost::filesystem to restrict access to actually existing files.

CapelliC
  • 59,646
  • 5
  • 47
  • 90
3

On Linux you can do it :

1) Create a DIR pointer, Open the directory using opendir()

DIR *ptr = opendir( path_of_directory );

2) Create struct dirent pointer, Read the file from directory using readdir();

struct dirent *ptr = readdir(ptr); //pass the DIR pointer

3) Run the above in a while loop. Push_back the data in a vector which is passed to this function as reference or return the vector.

4) Make sure that "." and ".." is not a file, so dont push that in vector. // To check this you can use std::strcmp( dirent_pointer->d_name, "." ) == 0 so.. if( !std::strcmp( ptr->d_name, "." ) == 0 )

Hope that helps

Biraj Borah
  • 101
  • 8
2

As in the example by SHR, you need to scan the directory and get files. You can use the Windows-specific implementation, or the functions in dirent.h on every Unix platform.

See this question for more information about dirent.h on Unix.

Community
  • 1
  • 1
G B
  • 2,951
  • 2
  • 28
  • 50
1

You can use boost::filesystem. However, this is not a header only library and you may have requirements not to link with external libraries or it may be very inconvenient to do so. On Windows (which looks like you are) I like to use this class to get all the filenames matching given pattern.

#pragma once
#include <string>
#include <vector>
#include <windows.h>

#pragma comment(lib, "User32.lib")

#undef tstring
#undef tcout
#if defined(_UNICODE) || defined(UNICODE)
#define tstring std::wstring
#define tcout std::wcout
#else
#define tstring std::string
#define tcout std::cout
#endif

class FileFinder {
  WIN32_FIND_DATA ffd;
  HANDLE _handle;

public:
  FileFinder(LPCTSTR pattern) { _handle = FindFirstFile(pattern, &ffd); }
  ~FileFinder() { FindClose(_handle); }
  const TCHAR *FindFirst() const {
    return _handle != INVALID_HANDLE_VALUE ? ffd.cFileName : nullptr;
  }
  const TCHAR *FindNext() {
    return FindNextFile(_handle, &ffd) ? ffd.cFileName : nullptr;
  }
  std::vector<tstring> GetAllNames() {
    std::vector<tstring> result;
    for (auto name = FindFirst(); name; name = FindNext())
      result.push_back(name);
    return result;
  }
};

It follows RAII paradigm and will not leak resources due to an exception. Example of it's usage could be like this.

#include <tchar.h>
#include <iostream>
#include "FileFinder.h"

int _tmain(int argc, TCHAR *argv[]) {
  DWORD dwError = 0;

  if (argc != 2) {
    _tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
    return -1;
  }

  tstring pattern(argv[1]);
  pattern.erase(pattern.find_last_not_of(TEXT("\\")) + 1);
  pattern += TEXT("\\*.pgm");
  if (pattern.length() > MAX_PATH) {
    _tprintf(TEXT("\nDirectory path is too long.\n"));
    return -1;
  }
  FileFinder finder(pattern.c_str());
  auto files = finder.GetAllNames();
  for (const auto &f : files)
    tcout << f << std::endl;
  return 0;
}
Vlad
  • 179
  • 1
  • 5