Link to home
Start Free TrialLog in
Avatar of stanisla
stanisla

asked on

I need to read all the xml files from a directory

I have a directory  c:\testxmls and in there I have many xmls files. I don't know the full names of xmls ahead of time. Using C++ that runs on both windows and linux I need to write code that will read each xml in the directory and save the name in a vector. Can you please provide me with full code that will do this. We also have boost version 1_33_1 so feel free to provide boost code if it's not possible with regular C++.

Thanks in advance
Avatar of jkr
jkr
Flag of Germany image

If you want that to be cross-platform, Boost would indeed be the way to go, e.g. (code taken from http://www.daniweb.com/forums/thread74944.html#)
#include <iostream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace boost::filesystem; 
using namespace std;
 
void show_files( const path & directory, bool recurse_into_subdirs = true )
{
  if( exists( directory ) )
  {
    directory_iterator end ;
    for( directory_iterator iter(directory) ; iter != end ; ++iter )
      if ( is_directory( *iter ) )
      {
        cout << iter->native_directory_string() << " (directory)\n" ;
        if( recurse_into_subdirs ) show_files(*iter) ;
      }
      else 
        cout << iter->native_file_string() << " (file)\n" ;
  }
}

Open in new window

BTW, a pure Windows solution would be that hre: http://msdn.microsoft.com/en-us/library/aa365200.aspx ("Listing the Files in a Directory"):
#include <windows.h>
#include <tchar.h> 
#include <stdio.h>
#include <strsafe.h>
 
void ErrorHandler(LPTSTR lpszFunction);
 
int _tmain(int argc, TCHAR *argv[])
{
   WIN32_FIND_DATA ffd;
   LARGE_INTEGER filesize;
   TCHAR szDir[MAX_PATH];
   size_t length_of_arg;
   HANDLE hFind = INVALID_HANDLE_VALUE;
   DWORD dwError=0;
   
   // If the directory is not specified as a command-line argument,
   // print usage.
 
   if(argc != 2)
   {
      _tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
      return (-1);
   }
 
   // Check that the input path plus 2 is not longer than MAX_PATH.
 
   StringCchLength(argv[1], MAX_PATH, &length_of_arg);
 
   if (length_of_arg > (MAX_PATH - 2))
   {
      _tprintf(TEXT("\nDirectory path is too long.\n"));
      return (-1);
   }
 
   _tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]);
 
   // Prepare string for use with FindFile functions.  First, copy the
   // string to a buffer, then append '\*' to the directory name.
 
   StringCchCopy(szDir, MAX_PATH, argv[1]);
   StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
 
   // Find the first file in the directory.
 
   hFind = FindFirstFile(szDir, &ffd);
 
   if (INVALID_HANDLE_VALUE == hFind) 
   {
      ErrorHandler(TEXT("FindFirstFile"));
      return dwError;
   } 
   
   // List all the files in the directory with some info about them.
 
   do
   {
      if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
      {
         _tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);
      }
      else
      {
         filesize.LowPart = ffd.nFileSizeLow;
         filesize.HighPart = ffd.nFileSizeHigh;
         _tprintf(TEXT("  %s   %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
      }
   }
   while (FindNextFile(hFind, &ffd) != 0);
 
   dwError = GetLastError();
   if (dwError != ERROR_NO_MORE_FILES) 
   {
      ErrorHandler(TEXT("FindFirstFile"));
   }
 
   FindClose(hFind);
   return dwError;
}
 
 
void ErrorHandler(LPTSTR lpszFunction) 
{ 
    // Retrieve the system error message for the last-error code
 
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 
 
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );
 
    // Display the error message and exit the process
 
    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 
 
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

Open in new window

Oh, and for the sake of being complete, here's how yu'd do that in Linux/UN*X:
#include <sys/types.h>
#include <dirent.h>
 
int main(int argc, char **argv)
{
DIR *dirHandle;
struct dirent * dirEntry;
 
  dirHandle = opendir("."); /* open current dir */
  if (dirHandle) {
    while (0 != (dirEntry = readdir(dirHandle))) {
        puts(dirEntry->d_name);
    }
    closedir(dirHandle);
  }
}

Open in new window

Avatar of stanisla
stanisla

ASKER

jkr,

I need to use the first solution because the code needs to run on both windows and linux but I'm getting a runtime exception below on line "if( exists( directory ) )"

      {"boost::filesystem::path: invalid name "C:\testxmls" in path: "C:\testxmls""}      std::basic_string<char,std::char_traits<char>,std::allocator<char> >

Any ideas?
You heed to double the backslash, since it is an escaope character in C++, i.e.
show_files( "C:\\testxmls" ) ;

Open in new window

I did initially. It throws the same exception I mentioned earlier.
Here is my code snippet.

inputXMLPath = "C:\\testxmls";
if ( exists( inputXMLPath ) )
{
      directory_iterator end_iter;
      for ( directory_iterator dir_itr( inputXMLPath );dir_itr != end_iter; ++dir_itr )
      {
            if ( is_directory( *dir_itr ) )
                 cout << dir_itr->native_directory_string() << " (inputXMLPath )\n" ;
            else
                 cout << dir_itr->native_file_string() << " (file)\n" ;
      }
}
catch(exception & exp)
{
      string errDesc = exp.what();
      cout << errDesc << endl;
}
Hm, stupid question: Does that directory exist and is the name exactly like that (no uppercase letters etc.)?
yes, I just confirmed that it's there
and the name is exact
Hm, does

inputXMLPath = "C:/testxmls";

work?
Nope, now I'm getting the following exception

+      errDesc      {"boost::filesystem::path: invalid name "C:" in path: "C:/testxmls""}      std::basic_string<char,std::char_traits<char>,std::allocator<char> >
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
That did it. Thanks