Home > database >  How to read a file in reverse in c using low level IO calls only
How to read a file in reverse in c using low level IO calls only

Time:11-08

How can I read a file in reverse using read, write, and open only no fwrite or any other f- related methods? Thanks in advance

I do not know where to begin with this. I have tried to look online but they use fopen or fprint or fgets, etc. I only know how to read and write a file.

CodePudding user response:

This should do, if you're using linux:

#include <fcntl.h> /* open() */
#include <unistd.h> /* close(), read(), lseek */

#include <stdio.h>

#define FILE_PATH "/path/to/the/file/to/print"

static void goToPositionInFile(int fileDescriptor, int position)
{
    lseek(fileDescriptor, position, SEEK_SET);
}

static void goToEndOfFile(int fileDescriptor)
{
    lseek(fileDescriptor, -1, SEEK_END);
}

static int positionInFile(int fileDescriptor)
{
    return lseek(fileDescriptor, 0, SEEK_CUR);
}

static void printFileBackwards(int fileDescriptor)
{
    char character;
    int position;

    goToEndOfFile(fileDescriptor);

    do
    {
        position = positionInFile(fileDescriptor);
        read(fileDescriptor, & character, 1);
        write(1, & character, 1); /* first argument: target file (stdout) */
        goToPositionInFile(fileDescriptor, position - 1);
    } while (position > 0);
}

static void openAndPrintFileBackwards(char const * const filePath)
{
    int fileDescriptor = open(filePath, 0);
    printFileBackwards(fileDescriptor);
    close(fileDescriptor);
}

int main(void)
{
    openAndPrintFileBackwards(FILE_PATH);

    return 0;
}
gcc -ansi -Wall -Wextra -Werror foo.c -o foo 
./foo

If you want to buffer the file, you'll need an array, to get the required size:

#include <sys/stat.h>

static long fileSizeInBytes(int fileDescriptor)
{
    struct stat fileStats;
    fstat(fileDescriptor, & fileStats);
    return fileStats.st_size;
}

Manuals, if something doesn't work on your system:

man 2 open
man 2 close
man 2 read
man 2 write
man fstat

CodePudding user response:

First, there will always be a TOCTOU bug potential present when reading a file backwards - there's no atomic "read the last byte of the file" functionality. Seeking to the end and then reading is not atomic, nor is using [f]stat() or any other method to get the size of the file and then reading from offsets based on that number.

When you read a file from the start using a known-unique file descriptor with a known-unique associated file description, simply repeatedly calling read() until read() fails to return any data will not suffer from a TOCTOU bug.

With that caveat out of the way, as mentioned in the comments, this is one way to read a file backwards using pread() (proper headers and error checking omitted to prevent creation of a vertical scroll bar):

ssize_t readBackwards( const char *filename )
{
    int fd = open( filename, O_RDONLY );

    struct stat sb;

    fstat( fd, &sb );

    off_t offsetToRead = sb.st_size;
    ssize_t totalRead = 0;

    while ( offsetToRead > 0 )
    {
        offsetToRead--;

        char c;

        ssize_t result = pread( fd, &c, 1, offsetToRead );

        totalRead  ;
    }

    close( fd );

    return( totalRead );
}
    
  •  Tags:  
  • c
  • Related