第二讲 QB的文件操作.docx
《第二讲 QB的文件操作.docx》由会员分享,可在线阅读,更多相关《第二讲 QB的文件操作.docx(22页珍藏版)》请在冰豆网上搜索。
第二讲QB的文件操作
第二讲QB的文件操作
学习重点:
1、了解文件的概念和分类。
2、掌握文件的打开、关闭以及读文件、写文件的方法,并能熟练运用。
3、会创建数据文件测试程序的正确性。
学习过程:
在2004年2月江苏省青少年信息学奥林匹克竞赛委员会发布的“小学组初、复赛命题大纲(试用稿)”中指出:
(对于复赛)在适当的时候考虑引入对文件的输入操作。
在近几年的程序设计竞赛中,均引入了文件操作的内容,不少学生在竞赛时吃了很大的亏,因此掌握这部分内容,对学生来说尤其重要。
一、文件的概念
文件(file)也叫作文档,是存放在磁盘(包括硬盘、软盘、U盘、光盘)上的一批数据,每个文件必须有一个文件全名,用文件全名来指明文件。
文件全名包括盘符、若干级目录、文件名、文件类型。
例如:
d:
\mydir\basic\data.txt
这里,盘符=d:
,而且有三级目录,每个斜线引出一级目录,文件名=data,每级目录和文件名都不得超8个字符,文件类型=.txt,这是最常见的正文文件类型。
以下的文件名均合法:
C:
\a1.bas代表C盘根目录下的a1.bas文件。
C:
\qb\xue.dat代表C盘中qb子目录中的xue.dat文件。
A:
student.dat代表A盘中当前目录中的student.dat文件。
abc.bas代表当前盘、当前目录中的abc.bas文件。
我们知道,计算机的内存容量小,造价高,而且还有一个严重的缺点——易失性,就是说一旦关闭了电源,内存中的全部内容就统统丢失了。
为此人们引进了磁盘文件作为内存的补充。
那么文件有什么用途呢?
举例说吧,假如你是班级学习委员,编了一个记分的程序。
第一天你输入了10个同学的各科成绩,然后你就关机睡觉了。
第二天打开机器,你的数据就不翼而飞了,还得从头再来。
如果你会使用文件,那就好办了。
第一天你键入了一些数据,关机前把它们记入文件,即使关机了文件中的数据也不会丢失,第二天只要让QB打开文件并把其中数据读入到内存,就可以继续输入了。
还有一种情况应该使用文件。
如果一个程序需要读取许多数据,若是每次都从键盘敲入,那么既麻烦又容易出错。
我们可以把数据做成一个文件,并且让程序读取其中的数据。
这样一来程序可能具有更大的灵活性。
按照文件中数据的表现形式来分类,可以将文件分成正文文件和二进制文件。
正文文件也叫做ASCII文件,其中的数据都是由ASCII代码构成的,例如我们在QB下编写的BASIC语言源文件(类型为.BAS)。
正文文件是人制作的,或者是为人而制作的,是人所能看懂的文件,可以用DOS下的EDIT程序和WINDOWS下的记事本或写字板制作和阅读。
二进制文件是由许多二进制位构成的,由一个程序制作,由另一个程序阅读,人看不懂,如果用EDIT、记事本或写字板来阅读的话,会出现一片乱码。
例如在QB之下由源文件转换成的可执行文件(类型为.EXE),就是一种二进制文件。
相比之下,正文文件用处更大,足以应付通常的编程工作。
我们只介绍正文文件的有关操作,想了解二进制文件可以参看各种QB的教科书。
从计算机内存向外存传送数据,称为“写文件”,即向外存输出数据。
将外存文件中的数据向计算机内存传送,称为“读文件”,即将文件读入内存。
在QB中,文件是可读的,也是可写的,但是不能对同一个文件又读又写。
在程序中若想读、写文件数据,须经历三大步骤:
打开文件、读/写数据、关闭文件。
打开文件完成准备工作,关闭文件完成扫尾工作,而读/写数据完成的才是数据交换工作。
二、打开文件——OPEN语句
1、格式
打开文件要完成一些必要的准备工作,如在目录中找出要读的文件,创建要写的文件,放置文件指针。
打开文件使用OPEN语句,其格式为:
OPEN<文件名>FOR<读写方式>AS#<文件号>
其中:
文件名可以是字符串常量或字符串变量,指明欲读写的文件。
文件名通常采用文件全名,但是如果BASIC程序文件与它要读写的数据文件同在一个目录中,可以省略盘符和各级目录;如果程序文件与数据文件分别存放在同一个磁盘的不同目录中,可以省略盘符。
AS#后的文件号是1-255之间的任意一个整数,OPEN语句将它同文件名字等同起来,在后面的读写语句和关闭语句中只用文件号来指明文件。
读写方式指明了对文件的读写操作可以取以下三种之一:
INPUT:
读文件,将文件中的数据传送到内存变量。
例如:
OPEN“d:
\data\data1.txt”FORINPUTAS#1
表示打开d:
\data中的data1.txt文件,只能从文件读数据,以文件号1代表此文件。
在OPEN语句中指定的文件名必须确实已经存在于指定的位置,如果d:
\data中没有data1.txt,则认为发生错误,停止程序执行,因为不能从一个不存在的文件中读取数据。
打开文件时文件指针指向文件开头,执行读语句时从第一个记录开始顺序读取。
OUTPUT:
写文件,将内存中的数据传送到文件。
例如:
OPENa$FOROUTPUTAS#2
假设已经执行了a$=“e:
\data\data2.txt”,则打开e:
\data中的data2.txt的输出文件,只能向文件写数据,指定该文件的文件号为2。
如果e:
\data中没有data2.txt,系统以此文件名建立一个新文件;如果文件存在,不论原来是否有数据,打开后,文件指针指向文件开头,原有的数据全部消失,相当于建立一个新文件。
以OUTPUT方式打开文件时应十分小心,不要误删除原来文件中有用的数据。
APPEND:
扩充文件,将在文件后添加新的数据。
OPEN“data3.txt”FORAPPENDAS#3
表示打开QB系统文件所在目录中的data3.txt,首先在QB系统文件所在目录中寻找文件data3.txt,如果找到,把文件指针指向到文件末尾处;如没有找到,建立之,把文件指针指到文件开始处。
注意:
如果打开方式是INPUT,那么要打开的文件必须存在,否则出错。
对于另两种方式,文件不存在也不是错误,都将导致创建一个新文件,并使文件指针指向文件开始处。
若以OUTPUT方式打开的文件已经存在,则清除原有数据,并使文件指针指向文件开始处,因此以OUTPUT方式打开文件时应十分小心,不要误删除原来文件中有用的数据;若以APPEND方式打开的文件已经存在,则文件指针将指向文件末尾,意味着新数据都写在文件原有数据之后。
对一个文件以某种方式打开,则只能对其执行指定的操作,如用OUTPUT打开,就只能把数据从头到尾写到文件中,中间不能“读”,只有关闭后重新以INPUT打开才能读数据。
三、读文件——INPUT#语句、LINEINPUT#语句和EOF函数
所谓读文件就是从文件中取出字符串送入字符串变量,或者转换成数值送入数值变量。
使用的语句有INPUT#语句和LINEINPUT#语句,它们分别对应于INPUT语句和LINEINPUT语句。
1、INPUT#语句
一般格式为:
INPUT#<文件号>,<变量>[,<变量>]……
其作用是,从<文件号>所指明的文件中读数据,并把这些数据依次赋给各个指定的变量。
一条INPUT#语句至少读入一个数据,变量分为字符串变量和数值变量,因此文件中数据的次序必须同这条语句中的变量次序一致。
文件中的字符串数据可以用双引号界定,也可以用逗号或行尾作为结束,哪个先出现哪个起作用;用逗号或行尾结束的字符串不包含逗号和双引号,用双引号界定的字符串不包含双引号本身。
而数值数据可以用逗号、空格或行尾作为结束。
由于各变量对应的文件中的数据都可以行尾作为结束,所以每一个数据都可以独占一行。
在这一点,INPUT#同键盘输入语句INPUT显然不同,一个INPUT语句读取的多个数据必须同处一行。
2、LINEINPUT#语句
格式:
LINEINPUT#<文件号>,<字符串变量>
作用是从打开的正文文件中读取一行,赋给指定的字符串变量。
正文行上可以包含任何字符,如空格、逗号、双引号。
INPUT#语句是从文件中逐一读取数据,而LINEINPUT#语句一次就要读取文件中的一行数据。
3、EOF函数
格式:
EOF(<文件号>)
此函数的作用是判断是否已经读完了<文件号>指明的文件中的所有数据,如是得到真值,否则得到假值。
也就是说,测试文件是否结束,若结束,返回一个非0值。
在程序中可以根据此值决定是否继续读此文件。
例:
OPEN"a.txt"FORINPUTAS#1’打开文件a.txt准备读
DOWHILENOTEOF
(1)’只要未到达文件尾,就继续读
INPUT#1,a$,b,c’从文件中读出a$,b,c
PRINTa$,b,c’屏幕显示a$,b,c
LOOP
CLOSE#1’关闭文件a.txt,以便再次打开
PRINT’屏幕空一行
OPEN"a.txt"FORINPUTAS#1’再次打开a.txt准备读
DOWHILENOTEOF
(1)’只要未到达文件尾,就继续读
LINEINPUT#1,a$’用LINEINPUT#语句读一整行
PRINTa$’显示该行
LOOP
CLOSE#1’关闭1号文件
END
此程序首先打开文件a.txt,并用INPUT#语句反复读取,每次读取3个数据到变量a$、b、c中,直至读完为止。
文件中给出了INPUT#语句允许的各种数据格式。
第二次打开文件,而后用LINEINPUT#来读取文件的每一行到a$中,再把它显示到屏幕上。
下面给出了本程序的屏幕输出,其中前4行是第一个循环4次读取的3个变量的内容。
注意,如果显示的姓名中夹有逗号,在文件中这样的字符串只能放在双引号中。
后6行就是文件a.txt本来的样子。
Liming1589.37
Li,ming1589.37
Liming1589.37
Liming1589.37
----------------------------------------
Liming,15,89.37
"Li,ming"1589.37
"Liming",15,89.37
Liming
15
89.37
四、写文件——PRINT#语句和WRITE#语句
1、PRINT#语句
格式:
PRINT#<文件号>,[USING“<格式字符串>”];<输出项表>
功能:
写数据到#<文件号>所关联的文件中。
PRINT#语句的使用与屏幕输出语句PRINT相似,只不过前者把数据写入外存,后者把数据输出在屏幕上。
其中的文件号是打开文件时指定的。
输出项表由O个或多个表达式组成,它们的值将输出到文件中,如果为空,则在文件中输出一个空行。
在省略格式字符串的情况下,每个表达式后跟有一个逗号或分号,逗号表示采取紧凑格式——数值后留一个空格,分号在输出项之后将跳到下一个14倍数列。
最后一个输出项后还可跟有空格,表示输出后换行。
输出项可以包括函数TAB(n)和SPC(n),分别表示使输出位置跳到第n列和跳过n列。
如果使用了USING“<格式字符串>”,那么各输出项之间只能用分号隔开。
<格式字符串>描写了各个输出项的输出格式,其中的格式字符串可以有一个或几个输出格式,每个输出格式对应于一个输出项。
如果输出格式的个数少于输出项,则循环使用各输出格式。
每个输出格式由若干格式字符组成,格式字符有数值的和字符串的。
数值格式字符包括:
#代表一个数值位,如#######表示显示7位整数(包括负数的-号),不足7位左面补之以空格。
.小数点,如####.###表示显示实数,其中整数部分占7个位置,而后是小数点,最后是3位小数。
,放在小数点之前,表示用逗号把整数部分分为3位一组。
+符号,表示显示数值符号,对于正数显示+,负数显示-。
-放在输出格式的最后,表示把-号显示在负数数值之后。
^^^^放在###...之后,表示要采取指数形式显示,^的个数指明指数占4个位置。
**放在###...之前,表示数前的空位用*填充。
$$前,表示数前显示一个$。
**$放在###...之前,表示数前显示一个$,前空用*填充。
字符串格式字符包括:
&显示整个字符串。
!
显示字符串的第一个字符。
/n个空格/显示字符串的前n+2个字符。
_放在格式字符之前,则将此格式字符作为普通字符显示,__将显示一个_。
以上格式字符之外的其它字符,如果出现在格式字符串中,将被原样地显示在文件中。
例如:
a=1234.567:
b=-34.5678:
c$="abcdefgh"
OPEN"b.txt"FOROUTPUTAS#1
PRINT#1,"1,";a;b;c$;a
PRINT#1,"2,";TAB(20);a;SPC(5);b;c$;a
PRINT#1,"3,";a,b,c$,a
WRITE#1,4,a,b,c$,a
PRINT#1,USING"5,#####.##|";a;b
PRINT#1,USING"6,######^^^^|####.###^^^^^|";a;b
PRINT#1,USING"7,+#####.#|######.#-|";a;b;b;a
PRINT#1,USING"8,**#####,.#|$$#####.#|**$#####.#|";a;a;a
PRINT#1,USING"9,left$(c$,1)=!
|c$=&|_!
|_&|__|\\|";c$;c$;c$;
CLOSE#1
END
此程序展示了PRINT#和WRITE#语句的用法,特别是格式字符串的作用,下面给出的是本程序所生成的文件b.txt的全部内容,请读者对照上面的程序仔细阅读。
为便于对照,在每个PRINT#语句中都显示一个序号,可是在第7个PRINT#语句中由于格式项的个数多于输出项,所以序号也同格式项一起被重复显示了。
1,1234.567-34.5678abcdefgh1234.567
2,1234.567-34.5678abcdefgh1234.567
3,1234.567-34.5678abcdefgh1234.567
4,1234.567,-34.5678,"abcdefgh",1234.567
5,1234.57|5,-34.57|
6,12346E-01|-345.678E-001|
7,+1234.6|34.6-|7,-34.6|1234.6|
8,***1,234.6|$1234.6|***$1234.6|
9,left$(c$,1)=a|c$=abcdefgh|!
|&|_|abcd|
2、WRITE#语句
格式:
WRITE#<文件号>,<输出项表列>
用它写文件时能自动地在各数据项之间插入逗号,并给字符串加双引号,且不在正数前面设置空格。
用WRITE#语句写成的文件更适合INPUT#语句读取。
例:
比较下面两个程序产生的输出文件格式的不同
Open“ex.2”foroutputas#1
DO
INPUT"NAME:
",Name$
INPUT"AGE:
",Age
print#1,Name$,Age
INPUT"Addanotherentry";R$
LOOPWHILEUCASE$(R$)="Y"
CLOSE#1
Open“ex.1”foroutputas#1
DO
INPUT"NAME:
",Name$
INPUT"AGE:
",Age
WRITE#1,Name$,Age
INPUT"Addanotherentry";R$
LOOPWHILEUCASE$(R$)="Y"
CLOSE#1
当输入数据同样为:
NAME:
ccc
AGE:
12
NAME:
bbb
AGE:
11
时,ex.1与ex.2两个文件的内容分别为:
ccc12
Bbb11
"ccc",12
"bbb",11
3、PRINT和WRITE语句两者的不同点:
PRINT写入到文件中的数据若是字符串,没有引号;
若PRINT有多个输出项,则项与项之间有空格。
而WRITE语句若写入到文件中的数据是字符串,会自动添加引号;多个输出项之间会以“,”相隔。
五、关闭文件——CLOSE语句
格式:
CLOSE[#<文件号>][,#<文件号>]……
此语句可以有0个、一个或多个#<文件号>参数,将分别关闭所有的、一个或多个已打开的文件。
关闭文件完成必要的扫尾工作,包括修改目录以反映文件信息的改变,如文件的长度、修改日期。
尽管当程序结束时QB能自动关闭尚未关闭的文件,规范的做法仍然是让程序关闭自己打开的所有文件。
六、创建数据文件
创建数据文件用以测试程序的正确性
方法1:
使用QB程序产生数据文件
方法2:
直接用QB编辑好数据后存盘,扩展名可以自选。
方法3:
使用写字板或其他编辑软件写入需要的数据,扩展名一般选“.txt”(常用方法)
例:
有一个程序需要30个整数,范围1—100,每行3个数,共10行。
我们可以这样来建立符合条件的数据文件“A1.IN”
六、综合示例
下面给出几个综合性的例题:
前几个代表了通常涉及文件的习题和试题,最后一个算得上是一个应用实例,功能强,但程序简单,容易修改成真正的应用。
1111111
2222221
3333321
4444321
5554321
6654321
7654321
例1.拐角矩阵
【问题描述】
从指定文件中读取正整数,m,n,i和j,(1<=i,j<=n<=20),然后计算并显示n阶回形矩阵的第i行第j列元素的值(右图给出的是7阶回形矩阵)。
[输入输出]
文件输入:
(输入文件\L1\T1.DAT与QB系统文件处在同一磁盘上)
该文件的第一行为正整数m,表示下面有m组数据,每组数据均占一行。
每行均有三个正整数n,i和j(以空格分隔)。
表示要计算并显示n阶回形矩阵的第i行第j列的元素值。
输入文件样例:
3
723
754
771
屏幕输出:
共有m行,每行只有一个正整数,即根据对应的输入数据计算出的元素值。
对应上面的输入产生如下屏幕输出:
2
4
7
【问题分析】
观察此题中的拐角矩阵,会发现它呈现明显的规律:
在从对角线之上显示的是行号i,在其下方显示的是n+1-j。
程序要先打开文件,从文件中读取数据组数m。
而后在一个执行m次的循环结构中,先读取矩阵尺寸n、行号i和列号j,然后算出位于第i行第j列的元素值k,并显示之。
【程序清单】
REM2-1.BAS
OPEN"\L1\T1.DAT"FORINPUTAS#1
INPUT#1,m
FORI=1TOm
INPUT#1,n,i,j
IFi+j<=n+1THENk=iELSEk=n+1–j’判断元素值
PRINTk
NEXTI
CLOSE#1
END
例2.整数的拼接(2006年小学程序设计竞赛第4题)
【问题描述】
设有n个整数(3≤n≤10),将这些整数拼接起来,可以形成一个最大的整数。
例如n=3,三个整数分别为21,7,34,拼接后最大的整数为:
73421
[输入输出]
文件输入:
第一行一个整数n,表示有n个整数
第二行n个整数,数与数之间用一个逗号分隔。
(10个测试文件在“d:
\js\t2”目录中,文件名为:
JS41.IN-JS40.IN)
文件输出:
一个拼接后的最大的整数。
(10个输出文件在“d:
\js\t2”目录中,文件名为:
JS41.OUT-JS40.OUT)
【样 例】
输入 输出
3 73421
21,7,34
【问题分析】
题目明确写明输入文件和输出文件的具体目录和文件名,为了节约时间,我们采取常量+变量的方法,只从键盘输入文件名,而不输入目录和文件类型。
【程序清单】
REM2-2.BAS
INPUTA$’分别输入文件名JS41--JS40
B$="D:
\JS\T2\"+A$+".OUT"’产生具体的输出文件名
A$="D:
\JS\T2\"+A$+".IN"’产生具体的输入文件名
OPENA$FORINPUTAS#1
OPENB$FOROUTPUTAS#2
INPUT#1,N’从文件中读入整数N
DIMA$(N)
FORI=1TON
INPUT#1,A$(I)
NEXTI
FORI=1TON–1’拼接
FORJ=I+1TON
IFA$(I)+A$(J)NEXTJ
NEXTI
FORI=1TON
PRINT#2,A$(I);
NEXTI
CLOSE
END
练一练:
将此题改为10个测试文件的文件输出内容均在d:
\js\t2\JS2-2.OUT文件中。
(提示:
用扩充文件方式)
例3.蛇形矩阵(2004年小学信息学奥赛复赛第1题)
8657621
9774853
9068394
0815920
6172401
7526331
9843542
【问题描述】
从键盘输入正整数n,i和j,(1<=i,j<=n<=20),然后计算并显示n阶蛇形矩阵的第i行第j列元素的值(右图是7阶蛇形矩阵)。
[输入输出]
文件输入:
第一行一个整数K,表示有K组数据;其余每行3个整数N,I,J,表示要计算并显示n阶蛇形矩阵的第i行第j列的元素值,数与数之间用空格分隔。
(测试文件在“d:
\js\t3”目录中,文件名为:
L3.TXT)
文件输出:
输出到文件(L3.OUT),输出文件和测试文件在同一个目录。
每行只有一个正整数,即根据对应的输入数据计算出的元素值。
【样 例】:
输入 输出
53
7354
7444
9564
159128
20118
【问题分析】
题目明确写明测试文件的具体目录和文件名,可以直接在OPEN后面用具体的字符串常量来指明文件全名。
由于输出文件和测试文件在同一个目录中,因此可以省略具体的路径,只指明文件名。
【程序清单】
REM2-3.BAS
OPEN"D:
\JS\T3\L3.txt"FORINPUTAS#1
OPEN“L3.OUT”FOROUTPUTAS#2
INPUT#1,k
FORl=1TOk
INPUT#1,n,i,j
m=i
IFm>jTHENm=j
IFm>n+1-iTHENm=n+1-i
IFm>n+1-jTHENm=n+1-j
PRINT#2,m’将数据写入到2