Search code examples
c++directorypopenfseekftell

_popen(dir, rt) fseek(dir, and ftell() returns 0


In this code, the ftell(dir) returns 0. But when I read with fread_s(), all the intended text is appearing. Any idea why ftell() returns 0 in this situation ?

FILE* dir = _popen("dir", "rt");
    if (dir == NULL) {
        send(socket, "0", 10, 0);
        cerr << "\nerror opening dir" << endl;
        return;
    }
    int r = fseek(dir, 0, SEEK_END);
    if (r != 0) {
        send(socket, "0", 10, 0);
        cerr << "\nerror seeking end" << endl;
        return;
    }
    long dirLength = ftell(dir);
    fseek(dir, 0, SEEK_SET);
    cout << "dirLength " << dirLength << endl;
    char dirListLength[10];
    memset(dirListLength, 0, 10);
    sprintf_s(dirListLength, 10, "%u", dirLength);
    cout << "dirListLength " << dirListLength << endl;
    send(socket, dirListLength, 10, 0);

    long sentDir = 0;
    char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);
    while (fread_s(buffer, BUFFER_SIZE, sizeof(char), BUFFER_SIZE, dir) > 0) {
        send(socket, buffer, BUFFER_SIZE, 0);
        cout << buffer << endl;
        cout << 1 << endl;
        memset(buffer, 0, BUFFER_SIZE);
    }
    _pclose(dir);

Solution

  • The _popen function creates a pipe. Pipes are not ordinary files, it's a one-way byte-stream where data flows from one end of the pipe to the other (much like pipes in real life).

    If you were allowed to seek through the pipe then you can only seek forward. Any data you skip with the seek would be gone. So even if it was allowed to seek forward it would make no sense in seeking backward as there is no reverse direction in a pipe.

    Also getting the current position using ftell makes no sense, since the there really exists nothing before the "current" position in the stream, so the "current" position will always be the beginning.

    If you want to read output from a pipe dynamically, then you have to use dynamic allocation and reallocation. Which in C++ should usually be handled by std::vector or std::string.