Solved

how do you list all the txt files from a folder using c++

Posted on 2011-02-25
31
422 Views
Last Modified: 2012-05-11
Hi, what function and header do you have to use to list all the txt files from a folder.

could you also give a very simple SAMPLE code?

Thanks a lot.
0
Comment
Question by:pgmerLA
  • 9
  • 8
  • 4
  • +4
31 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34980910
For which environment?
0
 

Author Comment

by:pgmerLA
ID: 34981063
MS VS 2008
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 34981361
Take a look at http://msdn.microsoft.com/en-us/library/aa365200%28VS.85%29.aspx ("Listing the Files in a Directory") - modified for a *.txt extension, that would be
#include <windows.h>
#include <tchar.h> 
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")

void DisplayErrorBox(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 3 is not longer than MAX_PATH.
   // Three characters are for the "\*" plus NULL appended below.

   StringCchLength(argv[1], MAX_PATH, &length_of_arg);

   if (length_of_arg > (MAX_PATH - 3))
   {
      _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("\\*.txt")); // <---------- only look for *.txt!

   // Find the first file in the directory.

   hFind = FindFirstFile(szDir, &ffd);

   if (INVALID_HANDLE_VALUE == hFind) 
   {
      DisplayErrorBox(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) 
   {
      DisplayErrorBox(TEXT("FindFirstFile"));
   }

   FindClose(hFind);
   return dwError;
}


void DisplayErrorBox(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 clean up

    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

0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 33

Expert Comment

by:sarabande
ID: 34981941
a portable solution you can get by downloading dirent.h for windows.

you also can make quick and dirty

   system("dir /b c:\\temp\\*.txt > temp_txtfiles.log");

and then read the temp_txtfiles.log.

note, system call is not recommendable for gui application cause a console window would pop-up.

Sara

0
 

Author Comment

by:pgmerLA
ID: 34982494
Could you give me a simple sample using findnextfile() in MS VS 2008
0
 
LVL 32

Expert Comment

by:phoffric
ID: 34982808
Take a look at http://www.experts-exchange.com/Programming/Languages/C/Q_26654614.html
Here are some excerpts (please review the above question for more details):

Use dirent.h functions, opendir(), readdir(), and closedir()

Portable code Reference (not just for Unix): http://www.ibm.com/developerworks/aix/library/au-unix-readdir.html

If you want to keep your program portable, you can use ftell and fseek to determine the filesize (in bytes). You would have to fopen the filename using binary.
    http://www.cplusplus.com/reference/clibrary/cstdio/fseek/
    http://www.cplusplus.com/reference/clibrary/cstdio/ftell/
    http://www.cplusplus.com/reference/clibrary/cstdio/fopen/

But, if want the permissions, group, owner, and date as well, then you will have to use non-standard C functions.


dir = opendir( "some/path/name" )  
entry = readdir( dir )  
while entry is not NULL:  
    do_something_with( entry )  
    entry = readdir( dir )  
closedir( dir )

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 34984414
>>Could you give me a simple sample using findnextfile() in MS VS 2008

That is what I posted above...
0
 
LVL 86

Expert Comment

by:jkr
ID: 34984455
Or, in an nutshell:
#include <windows.h>

void main () {

	WIN32_FIND_DATA fd;

	HANDLE hFind = FindFirstFile(_T("c:\\path\\*.txt"),&fd);

	while (hFind) {

		wprintf(_T("File: %s\n""),fd.cFileName);

		if (!FindNextFile(hFind,&fd)) break;
	}
}

Open in new window

0
 
LVL 2

Expert Comment

by:basavaraj_kn
ID: 34986787
Hi

You can use below, this pushes the file name with path to a vector, which you can use for your purpose.

You need to include headers #include <sys/types.h> and #include <dirent.h> to read the directory, you can use #include <errno.h> to know about any error in opening of file

try the below code, it should work for you

#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <string>
#include <iostream>


int listDirectoryFiles (std::string strDirName, std::vector<string> &dirFiles, bool listNestedDir=false, std::string fileNamePrefix="/")
{
	DIR *ptrDir;
	ptrDir = opendir(strDirName.c_str())

	if(ptrDir == NULL)
	{
		std::cout << "Last error: " << errno << ", in opening directory " << strDirName << std::endl;
		return errno;
	}


	struct dirent *ptrDirEntry;
	while ((ptrDirEntry = readdir(ptrDir)) != NULL)
	{
		if ( ptrDirEntry->d_type == DT_REG) //If this is a file
		{
			std::string fileName = fileNamePrefix;
			fileName += ptrDirEntry->d_name;
			dirFiles.push_back(fileName);
		}
		else if (ptrDirEntry->d_type == DT_DIR) //Directory
		{
			if ( listNestedDir )
				listDirectoryFiles ( ptrDirEntry->d_name, dirFiles, listNestedDir, ptrDirEntry->d_name );
		}

	}

	closedir(ptrDir);

	return true;
}

Open in new window


Thanks
Basavaraj
0
 
LVL 33

Expert Comment

by:sarabande
ID: 34991465
assuming you would like c++ sample code for ANSI text files only, the 'nutshell' code of jkr would turn to the code below.

you would need to create a win32 console project with the MultiByte Characterset  (and not UNICODE).

Sara
#include <iostream>
#include <windows.h>

int main () 
{
   WIN32_FIND_DATA fd;

   HANDLE hFind = FindFirstFile("c:\\path\\*.txt"),&fd);
   if (hFind == INVALID_HANDLE_VALUE)
      return GetLastError();

   do 
   {
      std::cout << "File: " << fd.cFileName << std::endl;
   } 
   while (FindNextFile(hFind, &fd) != NULL);
   if (GetLastError() != ERROR_NO_MORE_FILES)
      return GetLastError();
   FindClose(hFind);
   return 0;
}

Open in new window

0
 
LVL 33

Expert Comment

by:sarabande
ID: 34991471
In call of FindFirstFile remove the closing ) after the search path.

Sara
0
 

Author Comment

by:pgmerLA
ID: 34992507
Hi Sara,
Thanks for the code.
could you please add documentation for the code.
I don't understand a lot of the lines.
Thanks a lot.
0
 
LVL 86

Expert Comment

by:jkr
ID: 34992531
pgamerLA, sarabande knows prefectly well that posting slightly altered code is not welcomed at EE. May I ask you on the other side why you are ignoring what was posted before?
0
 
LVL 33

Expert Comment

by:sarabande
ID: 34995270
jkr, sorry for having angered you.

i did change the code cause it was pure c and and not c++ even when it would compile with a c++ compiler. it also uses proprietary T-switch of microsoft which in my opinion is not a part of a proper solution. i also added correct handling of the return codes.

i also made a reference to your code and did not pretend it was mine. sorry, if it wasn't correct nevertheless. i am still a beginner here in ee.

Sara



0
 
LVL 33

Expert Comment

by:sarabande
ID: 34995690
the

   while (hFind)

in the code of jkr would lead into an endless loop in case the handle is invalid, what is the case if the initial call to FindFirstFile failed. the return value then is -1 (== INVALID_HANDLE_VALUE) what would be 'true' when used in while condition.

if you look to all changes i made to the code of jkr it is more than slightly changed.

Sara
0
 
LVL 33

Expert Comment

by:sarabande
ID: 34995714
pgamerLA, please ask for the code lines you don't understand so that all who were particpating can answer your questions.

Sara
0
 

Author Comment

by:pgmerLA
ID: 35063130
Hi SaraBande,

I am having issues with the code. I get a compiling error. I am using MS VS 2008.

Could you please tell me where I made a mistake?

Thanks.
#include <iostream>
#include<windows.h>

int main()
{ WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(("c:\\Documents and Settings\\Massoud\\My Documents\\Visual Studio 2008\\*.txt"),&fd);
if (hFind ==INVALID_HANDLE_VALUE) return GetLastError();
do
{std::cout<<"File: "<<fd.cFileName<<std::endl;
}while(FindNextFile(hFind, &fd) != NULL);
if (GetLastError() != ERROR_NO_MORE_FILES) return GetLastError();
FindClose(hFind);
return 0;
}

Open in new window

0
 
LVL 11

Expert Comment

by:DeepuAbrahamK
ID: 35065897
What  you have posted above just works fine. What is the compilation error? If you can put all the details while posting will help you get quick answers from the Experts here.
0
 
LVL 33

Expert Comment

by:sarabande
ID: 35067271
I compiled with VS2008 and had no problems.

you should have a win32 console project with multi-byte characterset and precompiled headers off.

the settings can be made in project - properties (you find the character set in 'Configuration Properties - General and precompiled headers in Configuration Properties - C++ - Precompiled Headers).

Sara
0
 

Author Comment

by:pgmerLA
ID: 35079358
WOW.
It works!

can you tell what's the difference between using win32 console project and win32 project?(why use one and not the other)

and why we used multi-byte character set as opposed to the default version?

Thanks a lot Sara.
0
 
LVL 33

Expert Comment

by:sarabande
ID: 35081326
win32 console project expects main (or _tmain) as start function while win32 project expect WinMain function. the latter is supposed to already have initialisations for Windows what means a graphical user interface. if you don't have a WinMain function in a Win32 project normally the linker complains because of the missing start function.

the initial character set for Visual Studio projects can be UNICODE (more precisely UTF.16 what is 16-bit layer 0 of UNICODE) or Multi-Byte. the latter normally is named ANSI and is equivalent in codes 0 ... 255 (== 2^8 codes) to UTF-16 which has a maximum of 65536 (2^16) codes. though called multibyte it actually is a single-byte (8-bit) character set while UTF-16 is a double-byte character set.

those settings are relevant when using WINAPI functions which have character arrays or character pointers as arguments. then these types were defined as TCHAR arrays or LPTSTR pointers (and more). those types will map to char, char *, ... in case of multibyte character set and map to wchar_t, wchar_t * when UNICODE is set. So, you can get compiler errors if you pass a char* to GetCurrentDirectory and UNICODE is switched on cause GetCurrentDirectory expects a buffer of wide characters wchar_t. they also can lead to errors if you have a _tmain function rather than main cause the LPTSTR [] array argument would map to wchar_t * [] and not to char * [].

Sara
0
 

Author Comment

by:pgmerLA
ID: 35091994
thanks a lot.
0
 

Author Comment

by:pgmerLA
ID: 35110350
I somewhat agree with you.
However, I asked for a "very SIMPLE" code in my original question. I am only in my second class in C++ programming.
I felt that Sarabande answered my question by providing a simple code.
I have not doubt that jkr's code is great, but the code seems really hard(at this point).
I am new to EE. What do you suggest I do?
0
 

Author Comment

by:pgmerLA
ID: 35122615
Hi Vee Mod,
I think it's a great idea. Let's do it.
0
 

Author Comment

by:pgmerLA
ID: 35122994
Hi SaraBande,

could you post your answer on this page so that I can reward you for your code?

http://www.experts-exchange.com/Programming/Languages/CPP/Q_26883661.html
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question