Listing contents of a directory.

closed account (4Gb4jE8b)
What i want to be able to do is to search the contents of a directory and then display only those contents that end in .txt. I know that the common header for directory work is direct.h, and i understand mkdir and chdir. But that's really it. Can anyone point me to some reading that will enlighten me?

i've tried

http://www.devarticles.com/c/a/Cplusplus/Directories-in-Cplusplus/
http://www.dreamincode.net/forums/topic/60036-accessing-directories-in-cc-part-ii/
http://www.digitalmars.com/rtl/direct.html

and none really helped me understand how to do what i need to do.
Working with directories is platform specific due to different file systems.
Here is an example on windows (honestly I didn't attempt it till i had a strong understanding of file systems and c++)

http://msdn.microsoft.com/en-us/library/aa365200(v=vs.85).aspx
Here's something I helped someone write that runs on anything with a half-decent dirent.h (which is sadly not windows, but there are alternatives you can use if windows is your thing).

It's written in straight C, as per his needs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include "stdio.h"
#include "dirent.h" /* NOT PRESENT on all systems */
#include "stdlib.h"
#include "sys/stat.h"

// The key function is used recursively, and this value must be maintained across all recursions.
// Alternatively, could make it a parameter to the key function
int dirDepth; // Keep count of how deep into the directory tree we are.
char permissions[10]; // An array of ten characters that will be used to show the ten
                      //  characteristics of interest (file/dir, read/write/execute 
                      //  permissions for owner/group/others
 
// listContents is a function that returns an int, intended to be used for indicating
//  success or failure. It takes a pointer to a constant character (i.e. an array of
//  characters that identifies a location in the filesystem - it is constant to remind
//  the coder/maintainer not to mess with it, as it's of vital importance)
int listContents(const char *path) {

  int i = 0; /* Loop counter used later */
  struct dirent *entry; /* THIS STRUCT DIFFERS ACROSS SYSTEMS - THIS IS NOT PORTABLE CODE */
  DIR* p_startingDirectory; // a pointer to an object of type DIR. Type DIR is a structure
                                        //  representing a directory stream. Defined in dirent.h
                                         //  Note that at this point, the pointer exists but does not point 
                                        //  to a valid structure, as one has not been created
 
  p_startingDirectory = opendir(path); // Creates the directory stream, returns a pointer to it.
                                                        // The structure will be tidied up later with closedir
  if (p_startingDirectory == NULL) // Error check for good return from above
  {
    perror("opendir");
    return -1; // -1 is the return code that listContents returns to indicate failure.
                    //  perror dumps useful info to stderr
  }
 
  while((entry = readdir(p_startingDirectory))) // If readdir fails, entry will be null and
                                                                     //  while loop will end. Otherwise, entry will
                                                                    //  be a dirent struct. readdir returns the next entry
  {
    /* Do not list "." or ".." */
    if (!(strcmp(".", entry->d_name)))
    {
        continue; // back to start of while loop (which causes a fresh evaluation of the while condition,
                      // so changes entry
    }
    if (!(strcmp("..", entry->d_name)))
    {
        continue;
    }
 
    /* Get stat details */
    struct stat buf;
    
    /* Blank existing permissions for new file or dir */
    for (i=0;i<10;++i)
    {
      permissions[i]='-'; // Just as in ls -l
    }
    
    // Build complete pathname for this file or dir
    // How much memory do we need for the new path? This much.
    char* completePath = malloc(snprintf(NULL, 0, "%s/%s", path, entry->d_name) + 1);
    // snprintf prints the complete path and name and a 's' to NULL. Snprintf returns the number of
      // characters written.
    //  add one because C-style strings are array of char finishing with the value (NOT character)
    // zero.
    //  Feed that value to malloc, get back a void* to some memory. Cast it to a char*.
     // Strictly speaking, should do some kind of error checking to ensure that malloc returned 
       // memory
   
    // Now create completePath, which is what it sounds like
    sprintf(completePath, "%s/%s", path, entry->d_name);

    stat(completePath, &buf); // Fill buf with the details of file/dir specified by completePath
  
    // Mark each output as a file or a directory for the user
 
    if (entry->d_type == DT_DIR)
    {
      permissions[0]='d';
    }
    else if (entry->d_type == DT_REG)
    {
      permissions[0]='f';
    }

// Two examples showing how to get permissions. Used bitwise AND.
    if (buf.st_mode & S_IRUSR)
    {
      permissions[1]='r';
    }
    if (buf.st_mode & S_IWOTH)
    {
      permissions[8]='w';
    }
    
    /* Indent to show user directory contents */
    // Does NOT match the style of ls -R, but does make it clear to see
    for (i=0; i<dirDepth; ++i)
    {
      printf("  ");
    }

    printf("%s %zd %s \n", permissions, buf.st_size, entry->d_name ); // print to stdout permissions, size, name
    
    /* if this is a directory, go into it and start listing the contents */
    /* Go go Gadget recursion */
    if (entry->d_type == DT_DIR)
    {
        // Using dirDepth to make clear to the user which files are in which directory
        ++dirDepth; // So that we indent properly for subdirectories
        listContents(completePath);
        --dirDepth; // Now have come back out of the subdirectory, so un-indent
     }
    free(completePath); // Tidy up memory. If we malloced it, we must free it.
  }

  closedir(p_startingDirectory); // This also tidies up memory allocated by opendir
  return 0;
}
 
int main(int argc, char **argv) {
  int counter = 1; // For handling input arguments, although the only one we expect is the dir to 
                            // list.
                           //  enter multiple dirs, get multiple outputs
  dirDepth = 0;
 
  if (argc == 1)
	listContents(".");
 
  while (++counter <= argc) {
    printf("\nListing %s...\n", argv[counter-1]);
    listContents(argv[counter-1]);
  }
 
  return 0; // Indicate success with zero. Standard practice.
}


For your purposes, you'll need to wrap the printf statements in something to check for ending in ".txt"

Also, this code recurses through directories automatically; you will need to disable that (it's on line 97).
Last edited on
@Moschops:

Generally we don't give full solutions, I just realized I did the same thing you did though :O
I considered that, but it's not quite a full solution, I reckon, and to take out the bits not needed (and put in some extras) will require some understanding of it first; also, it's not quite what he's looking for, but should provide enough illumination upon reading to help figure out how to actually go about doing what he does need.

I wasn't sure, to be honest; if it's too close to a solution, I can obfuscate it a bit.
Last edited on
Ouch!

Try this: http://www.cplusplus.com/forum/unices/12452/
And this: http://www.cplusplus.com/forum/unices/3548/#msg15009

Once you get your list of files, you need to remove the ones you don't want. Using these useful utilities you can write yourself a helper to do that: http://www.cplusplus.com/forum/general/34348/#msg185786

1
2
3
#include <algorithm>
#include <string>
#include <vector> 
1
2
3
4
bool not_a_txt_file( const string& filename )
  {
  return ExtractFileExtension( filename ) != ".txt";
  }
1
2
vector <string> filelist = read_directory( "../mytxtfiles" );
filelist.erase( remove_if( filelist.begin(), filelist.end(), not_a_txt_file ), filelist.end() );

Hope this helps.
closed account (4Gb4jE8b)
To all of you, thanks for the help. I was able to do it as so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void listdir (const char *path)
{
	ostringstream c_content;
    DIR *c_dir = NULL;
	int startline, startlinep, endline = 0,length = 10;
    c_dir = opendir (path);
    struct dirent *contents = NULL;
    if (c_dir == NULL)
    {
        cout << "\nError: current directory could not be opened correctly";
		pause();
        return;
    }

    while (contents = readdir (c_dir))
    {
        if (contents == NULL)
		{
			cout << "\nError: current directory could not be read correctly";
			pause();
			return;
		}
		c_content << contents->d_name << "\n";
	}
	closedir(c_dir);
	string cdir_parse = c_content.str();

	//cout << cdir_parse;
	startlinep = cdir_parse.rfind('\n');

	for (;;)
	{
		endline = cdir_parse.rfind(".txt",startlinep);
		if(endline == -1){break;}
		startline = cdir_parse.rfind('\n',endline);
		length = endline - startline;
		cout << cdir_parse.substr(startline+1,length+4);
		startlinep = startline;
	}
	cout << "\n";
}
Topic archived. No new replies allowed.