dirent

Hi,

I am using <dirent.h> to get access to pictures in a folder and get their size.
This code runs, but the outcome states that all the pictures contained are size 1. I know this is impossible, but I can't figure out where the mistake is.
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
  #include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <typeinfo>
#include<iostream>

int main()
 {
    struct stat file_stats;
    DIR *dirp;
    struct dirent* dent;

    dirp=opendir("/home/Desktop/pics"); 
    do {
        dent = readdir(dirp);
        if (dent)
        {
            printf("  file \"%s\"", dent->d_name);
            printf(" is size %u\n", (unsigned int)file_stats.st_size);
            
          }
    } while (dent);
    closedir(dirp);
}
You didn't fill in the file_stats struct. You need to "stat" the file.

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
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
    const char *dir = "/home/Desktop/pics";

    if (chdir(dir) == -1) {
        perror(dir);
        return 1;
    }

    DIR *dirp = opendir(".");

    for (struct dirent *dent; (dent = readdir(dirp)) != NULL; )
    {
        const char *nm = dent->d_name;

        if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
            continue;

        struct stat file_stats;
        if (stat(nm, &file_stats) == -1)
            perror(nm);

        else
            printf("%9u: %s\n", (unsigned)file_stats.st_size, nm);
    }

    closedir(dirp);
    return 0;
}

Thank you.
Now I am a bit confused, may you please explain me how this works?

For instance, the first line const char *dir = "/home/Desktop/pics";
you don't use it again later,
instead, the parameter in line 17 is simply "."
Shouldn't the parameter be the actual path?
How does c++ know that you are referring to line 10 ?

What is line 23 doing ?

and line 27 ?


Thanks again.
dir is used in chdir (and the associated perror if there's an error).

"." refers to the current directory.
".." refers to the parent directory.
They exist in every directory, but are suppressed in normal directory displays. They do appear in readdir's output, though, so we need to skip them if we don't want to see them (and we pretty much never want to see them).

Since we chdir'ed to the directory we want to read, we need to open ".", the current directory.

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
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
    const char *dir = "/home/Desktop/pics";

    // Changing the current working directory to the directory we want
    // to read makes things easier since otherwise we need to strcat
    // the filenames to the directory before calling stat.
    if (chdir(dir) == -1) {
        perror(dir);
        return 1;
    }

    // Open current directory.
    DIR *dirp = opendir(".");
    if (!dirp) {
        perror("Can't open directory");
        return 1;
    }

    // Loop through the directory entries.
    for (struct dirent *dent; (dent = readdir(dirp)) != NULL; )
    {
        const char *nm = dent->d_name;

        // Skip "." and ".." dirs, which refer to the current and
        // parent directories, respectively.
        if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
            continue;

        // Call stat to fill in file_stats with the information.
        struct stat file_stats;
        if (stat(nm, &file_stats) == -1)
            perror(nm);

        else
            printf("%9u: %s\n", (unsigned)file_stats.st_size, nm);
    }

    closedir(dirp);
    return 0;
}

Last edited on
Thank you very much,
but what if instead of the size, you want to obtain the actual pictures?
What would replace line 43 ?
In other words:
if file_stats.st_size is of type integer, and 'nm' is of type 'string',
what would give me type 'bytes' ?
Last edited on
if file_stats.st_size is of type integer, and 'nm' is of type 'string',
what would give me type 'bytes' ?

None of that is correct!
st_size is type off_t (a signed integer, presumably long int or long long int).
nm is type char* and is a pointer to an array of chars that is zero-terminated.
And you are not looking for something of type 'bytes', but simply a way to open the file.
Since you have the filename, you can just use fopen.

So, for example, suppose you want to copy the files in the directory pics to a directory called copydir (that is also on the Desktop and already exists), then you could do the following.

BTW, I've been assuming all along that you want this in C (not C++), so that's how I've been doing it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        else {
            printf("%9lu: %s\n", (unsigned long)file_stats.st_size, nm);

            // Copy the files to another directory.
            // Assuming that directory 'copydir' exists at the
            // same level as pics (i.e., on the Desktop)

            // Create filename for output file.
            char outfile[1000];
            sprintf(outfile, "../copydir/%s", nm);

            // Copy the file in BUFSIZ chunks.
            char buf[BUFSIZ];
            FILE *fin = fopen(nm, "rb");
            FILE *fout = fopen(outfile, "wb");
            size_t cnt;
            while ((cnt = fread(buf, 1, sizeof buf, fin)) != 0)
                fwrite(buf, 1, cnt, fout);
            fclose(fout);
            fclose(fin);
        }

Last edited on
Well, I am using a C++ compiler, so I suppose that c++ lines are recommended, however, anytime I look for suggestions online, including this forum, I always find C lines squeezed here and there, since they work with this compiler too. I am for anything that works and runs smoothly.

With this being said, I am a bit confused by your code.
What I need is the actual bytes so I can send them via socket.
If I want to send only one image, this code works very well

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char file_name[] = {"/home/Desktop/pics/pic.jpeg"};
ifstream stream(file_name, std::ios::in | std::ios::binary);
vector<char> imageDataVec((istreambuf_iterator<char>(stream)), istreambuf_iterator<char>());
cout << "Size: " << imageDataVec.size() << " bytes";
long converted_number = htonl(imageDataVec.size());
//send(new_socket, &converted_number, sizeof(converted_number), 0);
//send(new_socket, &imageDataVec, imageDataVec.size() , 0);

size_t sent{};
while (sent < imageDataVec.size()) {
    int nbytes = send(new_socket, &imageDataVec[sent], imageDataVec.size() - sent, 0);
    if (nbytes <= 0) {
        std::clog << "error: while sending image\n";
        break;
    
    sent += nbytes;
    cout<<nbytes<<"================"<<endl;

}


However, as you can see from the first line, I have to open the file as a 'char'.
Now, given what you wrote above, how to incorporate your code by replacing the first line?
Is it even possible to do it this way, or I have to rewrite my whole code?
Last edited on
I am using <dirent.h> to get access to pictures in a folder and get their size.
This code runs, but the outcome states that all the pictures contained are size 1

So you need to figure out how to get the size.

what if instead of the size, you want to obtain the actual pictures?
Wait. So you don't need the size at all. You really want to access the contents of the files. Okay. open/close/read/write.

What I need is the actual bytes so I can send them via socket.

This is quite a moving target, and Dutch deserves a medal for being patient. If you're sending the files via a socket then you don't need to know the initial size at all - at least not with the code from your last post.

So please describe what you're actually trying to do. It can help us figure out if you have the right approach.

So you need to figure out how to get the size.


I got it, thanks. no longer an issue


This is quite a moving target, and Dutch deserves a medal for being patient


I have my way to do things, that's why I ask so many questions, believe it or not, knowing the size has been very helpful to me so far on the receiver side, and is always good to know how to do it anyway.
I am now trying to sending these files via socket, and I am not sure how to use dutch's code in order to achieve this task.
Any ideas ?
Last edited on
Conceptually, you want to replace dutch's write() statement (line 18) with your send loop (lines 11-18).
I have a question:

would it be a good strategy to
open the file this way
FILE *fin = fopen(nm, "rb");

and then, convert it to a char array, so I can use the rest of the code that I already have?
Is there perhaps a step that I am missing?

since this line
cout<<nbytes<<"================"<<endl;

prints that 0 bytes are sent
Last edited on
I have my way to do things
Really?
Conceptually, you want to replace dutch's write() statement (line 18) with your send loop (lines 11-18).

I have been trying for awhile, but I am not sure what I m doing wrong.
this line is printed error: while sending image\n

here is my code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char buffer[BUFSIZ];
FILE *fin = fopen(nm, "rb");
          
            size_t cnt;

            while ((cnt = fread(buffer, 1, sizeof buffer, fin)) != 0)
                {    int nbytes = send(new_socket, fin, conv_num, 0);
    if (nbytes <= 0) {
        std::clog << "error: while sending image\n";//this line is printed
        break;
    
    sent += nbytes;
    cout<<nbytes<<"================"<<endl;

}
Do these files have names? Do you need to transfer the names too?

If you're running the code on a camera then do you have enough RAM to hold an entire image at once?

For both of these reason's, I'd do this like so:
for each file in the directory
get the meta data (name, size, checksum, whatever else you need to transmit about the image)
send the meta data
send the file

To send the file:
open the file
open the socket
create a buffer
while ((read from file to buffer) returns positive value) {
send the bytes to the socket.
}

You need to be scrupulous about checking for errors and cleaning up when you get them.
I printed the names but I don't need to send them.
As you can tell from my code, I have already did everything you said:
open the file, socket,buffer etc...
yet, the outcome is still unsuccessful.

Now may I please know how to fix my code in order to make it work?
Does anyone know ?
Feel free to ask if you need more details.
Last edited on
Yeah, post ALL your code - both ends of it .
That means all the C++ and all the python.

Stop making us guess from your peephole hand wringing and show us exactly what you're working with.

please refer to my newer thread
Last edited on
Registered users can post here. Sign in or register to post.