3358 blog.csdn.net/libing 403/article/details/73158972
讨论三个问题: fseek 函数和ftell )函数的工作方式、二进制流的使用方式以及如何使程序可移植。
fseek 和ftell )的结构
头文件: #include
函数定义: int
seekfile*stream,long offset,int whence );
函数说明: fseek ) )用于移动文件流的读取/写入位置。
1 .参数stream是打开的文件指针。
2 .参数offset
是偏移量。 此参数表示从起始点移动的距离。 干参数必须是长类型的值。 正前进)、负后退)或0 ) )。
3 .参数whence
模式。 这个参数决定起点。 根据ANSI标准,stdio.h头文件中规定了几个表示模式的明确的标量例如
常数)。 如下表所示:
表1文件的起始点模式
模式
偏移的起点
SEEK_SET
文件开头
SEEK_CUT
文件的当前位置
SEEK_END
文件末尾
在的实现中可能缺少这些定义,并且这3种模式可以分别由数值0L、1L、2L表示。 l表示该值为长类型。
fseek ) )函数的一些调用示例。 fp是文件指针。
seekFP,0L,SEEK_SET ); //转到文件开头
seekFP,10L,SEEK_SET ); //移动到文件的第10个字节
seekFP,2L,SEEK_CUR ); //从文件的当前位置前进2个字节
seekFP,0L,SEEK_END ); //移动到文件末尾
fseekFP,-10,SEEK_END ); //从文件末尾后退10个字节
1
2
3
4
5
这些调用有一些限制。 稍后再解释。 如果一切正常,则fseek函数的返回值为0; 如果发生错误,例如,如果尝试移动到文件范围之外,返回值将为-1。
ftell ) )
函数用于获取文件读/写指针的当前位置。 其原型是长文件file * stream );
【参数】stream是打开的文件指针。
【返回值】成功时返回当前的读写位置,失败时返回-1。
对于二进制文件,返回从文件开头到文件末尾的字节数。
对于文本文件,返回的值可能没有实际意义,但可用于存储当前读写位置以供fseek )函数使用
随机访问文件时,文件的位置会频繁地前后移动,因此程序不容易确定文件的当前位置。 您可以使用fseek函数,然后调用函数ftell )来快速确定文件的当前位置。 ftell ) )
fseek ) )一起经常使用。
在第一个unix实现中,ftell )通过返回从文件开头开始的字节数来确定文件的位置。 的第一个字节到文件开头的距离为0。 美国航空
C规定,此定义适用于以二进制模式打开的文件,而对于以文本文件打开的文件则不同。
请看以下过程的示例。
#包含
#包含
#define CNTL_Z ‘\032 ‘
#define SLEN 81
入主void ) )。
{
char file[SLEN];
char ch;
FILE *fp
长计数,最后;
企业文件处理: puts );
Scanfs ),文件;
if ) FP=fopenfile,’ rb ‘ ) ) ==NULL ) ) ) ) ) ) ) ) ) )。
{
reverse can ‘ topen % s\n ‘,file );
exitexit_failure;
}
seekFP,0L,SEEK_END );
last=ftellFP;
forcount=1L; count=last; count )
{
seekFP,-count,SEEK_END );
ch=getcFP;
ifch!=CNTL_Z ch!=’\r ‘ )
Putcharch );
}
putcharn ) );
floseFP );
re
turn 0;
}
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
下面是该程序对一个文件的输出:
Enter the name of the file to be processed:
Cluv[用户输入]
.C ni naht ylevol erom margorp a
ees reven llahs I taht kniht I
1
2
3
4
5
6
注意,运行程序前先在可执行程序的目录下准备一个叫Cluv的文件,里面存有以下内容,才可能得到上面的输出笔者是在windows下Cygwin模拟的Linux环境下运行)。名为Cluv的文件:
I think that I shall never see
a program more lovely than in C.
1
2
3
该程序使用二进制模式,以便处理MS-DOS文本和UNIX文本。但是,是在使用其他格式的文本文件的环境可能无法正常工作。
首先,分析下面的语句:
fseekfp,
0L, SEEK_END);
把当前位置设置为距文件末尾0字节偏移量。也就是说,该语句把当前位置设置在文件结尾。下一条语句:
last=ftellfp);
把文件开始到文件结尾的字节数赋值给last。
然后是一个for循环:
for count = 1L; count <= last; count++)
{
fseekfp, -count, SEEK_END);
ch = getcfp);
if ch != CNTL_Z && ch != ‘\r’)
putcharch);
}
1
2
3
4
5
6
7
第一轮迭代,把程序定位到文件结尾的第一个字符即文件的最后一个字符)。然后,长须打印该字符。然后,程序打印该字符。下一轮迭代把程序定位到前一个字符,并打印该字符。重复这一过程直到文件的第一个字符,并打印。
二进制模式和文本模式
上面的示例程序在UNIX和MS-DOS环境下都可以运行。UNIX只有一种文件格式,所以不需要进行特殊的转换。但是MS-DOS要格外注意,许多MS-DOS编辑器都用Ctrl+Z标记文本文件的结尾。以文本模式打开这样的文件时,C能识别这个作为文件结尾标记的字符。但是,以二进制模式打开文件时,Ctrl+Z字符被看做文件中的一个字符,而实际的文件结尾符在该字符的后面。文件结尾符可能紧跟Ctrl+Z字符后面,或者文件中可能用空字符填充,使该文件的大小是256的倍数。在DOS环境下不会打印空字符,上面程序就包含了贩子打印Ctrl+Z字符的代码。
二进制模式和文本模式的另一个不同之处是:MS-DOS用\r\n组合表示文本文件换行。以文本模式打开相同的文件时,C程序把\r\n“看成”是\n。但是,以二进制模式打开该文件时,程序能看见这两个字符。因此,上面的程序还包含了不打印\r的代码。通常UNIX文本文件既没有Ctrl+Z,也没有\r,所以这部分代码不会影响大部分UNIX文本文件。
ftell函数在文本模式和二进制模式中的工作方式不同。许多系统的文本文件格式与UNIX的模型有很大的不同,导致从文件开始处统计的字节数称为一个毫无意义的值。ANSI
C规定,对与文本模式,ftell)返回值可以作为fseek)的第2个参数。对于MS-DOS,ftell)返回值把\r\n当做一个字符计数。
可移植性
理论上,fseek)和ftell)应该符合UNIX模型,但是,不同系统存在着差异,有时确实无法做到与UNIX模型一致。因此,ANSI
对这些函数降低了要求。下面是一些限制
在二进制中,实现不必支持SEEK_END模式。因此无法保证上面的程序的可移植性。移植性更高的方法是逐字节读取整个文件直到文件末尾。C预处理器的条件编译指令提供了一种系统方法处理这种情况。
在文本模式中,只有以下调用能保证其相应的行为。
函数调用
效果
fseekfile, 0L, SEEK_SET)
定位至文件开始处
fseekfile, 0L, SEEK_CUR)
保持当前位置不动
fseekfile, 0L, SEEK_END)
定位至文件结尾
fseekfile,ftell-pos, SEEK_SET)
到距文件开始处ftell-pos的位置,ftell-pos是ftell)的返回值
快三稳赚10大技巧END);
把当前位置设置为距文件末尾0字节偏移量。也就是说,该语句把当前位置设置在文件结尾。下一条语句:
last=ftellfp);
把文件开始到文件结尾的字节数赋值给last。
然后是一个for循环:
for count = 1L; count <= last; count++)
{
fseekfp, -count, SEEK_END);
ch = getcfp);
if ch != CNTL_Z && ch != ‘\r’)
putcharch);
}
1
2
3
4
5
6
7
第一轮迭代,把程序定位到文件结尾的第一个字符即文件的最后一个字符)。然后,长须打印该字符。然后,程序打印该字符。下一轮迭代把程序定位到前一个字符,并打印该字符。重复这一过程直到文件的第一个字符,并打印。
二进制模式和文本模式
上面的示例程序在UNIX和MS-DOS环境下都可以运行。UNIX只有一种文件格式,所以不需要进行特殊的转换。但是MS-DOS要格外注意,许多MS-DOS编辑器都用Ctrl+Z标记文本文件的结尾。以文本模式打开这样的文件时,C能识别这个作为文件结尾标记的字符。但是,以二进制模式打开文件时,Ctrl+Z字符被看做文件中的一个字符,而实际的文件结尾符在该字符的后面。文件结尾符可能紧跟Ctrl+Z字符后面,或者文件中可能用空字符填充,使该文件的大小是256的倍数。在DOS环境下不会打印空字符,上面程序就包含了贩子打印Ctrl+Z字符的代码。
二进制模式和文本模式的另一个不同之处是:MS-DOS用\r\n组合表示文本文件换行。以文本模式打开相同的文件时,C程序把\r\n“看成”是\n。但是,以二进制模式打开该文件时,程序能看见这两个字符。因此,上面的程序还包含了不打印\r的代码。通常UNIX文本文件既没有Ctrl+Z,也没有\r,所以这部分代码不会影响大部分UNIX文本文件。
ftell函数在文本模式和二进制模式中的工作方式不同。许多系统的文本文件格式与UNIX的模型有很大的不同,导致从文件开始处统计的字节数称为一个毫无意义的值。ANSI
C规定,对与文本模式,ftell)返回值可以作为fseek)的第2个参数。对于MS-DOS,ftell)返回值把\r\n当做一个字符计数。
可移植性
理论上,fseek)和ftell)应该符合UNIX模型,但是,不同系统存在着差异,有时确实无法做到与UNIX模型一致。因此,ANSI
对这些函数降低了要求。下面是一些限制
在二进制中,实现不必支持SEEK_END模式。因此无法保证上面的程序的可移植性。移植性更高的方法是逐字节读取整个文件直到文件末尾。C预处理器的条件编译指令提供了一种系统方法处理这种情况。
在文本模式中,只有以下调用能保证其相应的行为。
函数调用
效果
fseekfile, 0L, SEEK_SET)
定位至文件开始处
fseekfile, 0L, SEEK_CUR)
保持当前位置不动
fseekfile, 0L, SEEK_END)
定位至文件结尾
fseekfile,ftell-pos, SEEK_SET)
到距文件开始处ftell-pos的位置,ftell-pos是ftell)的返回值