Jun 01, 2021 Article blog
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.
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.
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.
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.
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.
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.
However, many common environments support more behavior.
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