Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Do you know how the C language handles the two I/O random accesses of fseek() and ftell()?


Jun 01, 2021 Article blog


Table of contents


This article will discuss how fseek() and ftell() functions work, how to use binary streams, and how to make programs portable.

With fseek() function, you can think of a file as an array and move it directly to any byte in a file opened by fopen() L et's create a program reverse.c demonstrate the use of fseek() and ftell() Note that long fseek() has three parameters that return the value of the int type; ftell()

/* reverse.c -- displays a file in reverse order */
#include <stdio.h>
#include <stdlib.h>
#define CNTL_Z '032'   /* eof marker in DOS text files */
#define SLEN 81
int main(void)
{
    char file[SLEN];
    char ch;
    FILE *fp;
    long count, last;


    puts("Enter the name of the file to be processed:");
    scanf("%80s", file);
    if ((fp = fopen(file,"rb")) == NULL)
    {                               /* read-only mode   */
        printf("reverse can't open %sn", file);
        exit(EXIT_FAILURE);
    }


    fseek(fp, 0L, SEEK_END);        /* go to end of file */
    last = ftell(fp);
    for (count = 1L; count <= last; count++)
    {
        fseek(fp, -count, SEEK_END); /* go backward      */
        ch = getc(fp);
        if (ch != CNTL_Z && ch != 'r')  /* MS-DOS files */
            putchar(ch);
    }
    putchar('n');
    fclose(fp);


    return 0;
}

Here's the output to a file:

Enter the name of the file to be processed: Cluv . C ni eno naht ylevol erom margorp a ees reven llahs I taht kniht I

The program uses binary mode to work with MS-DOS text and UNIX files. However, it may not work properly in environments that use text files in other formats.

If you run the program through a command-line environment, the pending file is in the same directory (or folder) as the executable file. I f you run the program in the IDE, the exact lookup sequence varies depending on the implementation. For example, by default, Microsoft Visual Studio 2012 looks in the directory where the source code is located, while Xcode 4.6 looks in the directory where the executable is located.

1 How fseek() and fell() work

The first parameter of fseek() is the FILE pointer, which points to the file to be found, and fopen() should have opened the file.

The second argument of fseek() is offset T his parameter represents the distance to be moved from the starting point (see the starting point pattern listed in Table 13.3). The parameter must be a value of the long type and can be positive (forward), negative (backward), or 0 (hold).

The third argument of fseek() is the pattern, which determines the starting point. According to ANSI standard, several express constants representing patterns manifest constant specified in the stdio.h header file, as shown in Table 13.3.

 Do you know how the C language handles the two I/O random accesses of fseek() and ftell()?1

These definitions may be missing from the old implementation and can be represented by the numeric values 0L、1L、2L respectively. L suffix indicates that its value is the long type. A lternatively, the implementation might define these express constants in a different header file. If you're not sure, check the implementation manual or online help.

Here are some examples of calling the fseek() function, fp is a file pointer:

fseek(fp, 0L, SEEK_SET);   // go to the beginning of the file
fseek(fp, 10L, SEEK_SET);  // go 10 bytes into the file
fseek(fp, 2L, SEEK_CUR);   // advance 2 bytes from the current position
fseek(fp, 0L, SEEK_END);   // go to the end of the file
fseek(fp, -10L, SEEK_END); // back up 10 bytes from the end of the file

There are some limitations to these calls, which we'll discuss later.

If all goes well, fseek() returns a value of 0, or -1 if an error occurs, such as an attempt to move a distance beyond the scope of the file.

The return type of the ftell() function is long which returns the number of bytes from the beginning of the file where the argument points to the file. ANSI-C defines it in stdio.h I n UNIX which was originally implemented, ftell() determines the location of the file by returning the number of bytes from the beginning of the file. T he distance from the first byte of the file to the beginning of the file is 0, and so on. ANSI C states that this definition applies to files that are opened in binary mode, and that opening files in text mode is different. This is why the program reverse.c opens the file in binary mode.

Let's analyze the basic elements of the program reverse.c First, the following statement:

 fseek(fp, 0L, SEEK_END);

Set the current position to an offset of 0 bytes from the end of the file. T hat is, the statement sets the current position at the end of the file. Next statement:

last = ftell(fp);

Assigns the number of bytes from the beginning of the file to the end of the file to last . Then there's a for loop:

for (count = 1L; count <= last; count++)
{
  fseek(fp, -count, SEEK_END);    /* go backward */
     ch = getc(fp);
 }

The first iteration positions the program to the first character at the end of the file (that is, the last character of the file). T he program then prints the character. T he next iteration positions the program to the previous character and prints the character. Repeat this process until the first character of the file is reached and printed.

2 Binary mode and text mode

We designed the program reverse.c to run in UNIX and MS-DOS environments. UNIX has only one file format, so no special conversion is required. MS-DOS however, should take extra care. M any MS-DOS editors mark the end of a text file with Ctrl+Z W hen you open such a file in text mode, C recognizes the character marked as the end of the file. H owever, when you open the same file in binary mode, Ctrl+Z character is considered a character in the file, and the actual file ending character is after that character. T he end character of the file may follow the Ctrl+Z character, or the file may be filled with empty characters, making the file a multiple of 256. Empty characters are not printed in DOS environment, and the program reverse.c contains code that prevents the printing of Ctrl+Z characters.

Another difference between binary and text patterns is that MS-DOS represents text file \r\n in a combination of . W hen you open the same file in text mode, \r\n C program "sees" \n as . H owever, when you open the file in binary mode, the program can see both characters. T herefore, the program reverse.c also contains code that does not \r . Typically, UNIX text files have neither Ctrl+Z nor \r so this part of the code does not affect most UNIX text files.

ftell() function works differently in text mode and binary mode. T he text file format of many systems is very different from UNIX model, resulting in a meaningless value in the number of bytes counted from the beginning of the file. ANSI C states that for text patterns, the value returned by ftell() can be the second argument of fseek() For MS-DOS the value returned by ftell() \r\n the value of the word as a byte.

3 Portability

In theory, fseek() and ftell() should conform to UNIX model. H owever, there are differences between systems, and sometimes it is not possible to be consistent with the UNIX model. A s a result, ANSI reduces requirements for these functions. Here are some restrictions.

  • In binary mode, the implementation does not have to support SEEK_END mode. T herefore, the portability of program listing 13.4 cannot be guaranteed. A more portable approach is to read the entire file by byte until the end of the file. The C preprocessor conditional compilation instruction (described in Chapter 16) provides a systematic way to handle this situation.

  • In text mode, only the following calls guarantee their corresponding behavior.

 Do you know how the C language handles the two I/O random accesses of fseek() and ftell()?2

However, many common environments support more behavior.

4 getpos() and fsetpos() functions

The potential problem with fseek() and ftell() is that they both limit file sizes to the range that the long type can represent. M aybe 2 billion bytes may seem quite large, but as storage capacity grows rapidly, so do files. W ith this in mind, ANSI C has added two new positioning functions for processing larger fgetpos() and fsetpos() T hese two functions do not use the value of the long type to represent the location, they use a new type: fpos_t (for file positiontype, file positioning type). fpos_t type is not a basic type, it is defined according to other types. fpos_t or data objects of the fpos_t type can specify a location in the file that cannot be an array type, except that there are no other restrictions. Implementations can provide a type that meets the requirements of a particular platform, for example, fpos_t can be implemented as a structure.

ANSI-C how to use fpos_t type. The prototype of the fgetpos() function is as follows:

nt fgetpos(FILE * restrict stream, fpos_t * restrict pos);

When the function is called, it places the value of fpos_t type at the position that pos to, which describes the number of bytes in the file whose current location is at the beginning of the file. If successful, fgetpos() function returns 0;

The prototype of the fsetpos() function is as follows:

: int fsetpos(FILE stream, const fpos_t pos);

When you call the function, use pos to point to the fpos_t type value at the location to set the file pointer to the location specified after the value is offset. I f successful, fsetpos() function returns 0; fpos_t value of the fpos_t type should be obtained by calling fgetpos() earlier.

These are two random access functions for C processing I/O fseek() and ftell() which I hope will help you. To learn more, you can take a look at the tutorial

C tutorial: https://www.w3cschool.cn/c/

Source: www.toutiao.com/a6855410553498632708