610 likes | 776 Views
第 16 章 文件应用. 有关的内容: 3 个文件系统的可视化的标准控件 ( 驱动器 , 目录 , 文件列表 ) Windows 通用文件对话框控件,用于指定或选择文件(打开或保存) 操作文件的语句和函数(学习不同类型文件的打开、关闭、读、写等) 和文件系统有关的语句和函数 使用文件系统对象来访问文件(学习有关对象的属性和方法). 文件的类型. 文件就是保存在磁盘上的字节,不同类型的文件有不同的结构,即字节之间的关系,以及每个字节表示什么内容(是整数、字符串还是数据记录等),根据这些结构我们将文件的类型划分为三类。 顺序文件
E N D
第16章 文件应用 有关的内容: • 3个文件系统的可视化的标准控件(驱动器, 目录, 文件列表) • Windows通用文件对话框控件,用于指定或选择文件(打开或保存) • 操作文件的语句和函数(学习不同类型文件的打开、关闭、读、写等) • 和文件系统有关的语句和函数 • 使用文件系统对象来访问文件(学习有关对象的属性和方法)
文件的类型 • 文件就是保存在磁盘上的字节,不同类型的文件有不同的结构,即字节之间的关系,以及每个字节表示什么内容(是整数、字符串还是数据记录等),根据这些结构我们将文件的类型划分为三类。 • 顺序文件 • 顺序文件保存为一个连续块,块中的字节代表的都是文本字符,读取和写入都是字符或字符串类型数据(ANSI字符),而且都是按照顺序进行的。 • 随机文件 • 当一个文本文件中含有多条记录,而且每条记录有固定统一的长度时,可以实现记录的随机访问。不一定是纯文本。 • 二进制文件 • 二进制文件则适用于读写任意结构的文件。二进制文件中的字节可以代表任何东西。只有精确地知道数据是如何写到文件中后,才可能对它进行正确的读取或检索。
文件访问的步骤 • 使用Open语句打开文件, 指定文件号和存取方式 • 从文件中读取数据到变量中 • 使用或处理变量中的数据, 或者保存变量中的数据到其它文件中 • 文件操作结束, 使用Close语句关闭文件
打开顺序文件 Open filename For [Input|Output|Append] As [#] FileNumber • FileNumber指定一个有效的文件号,1~511,使用FreeFile函数可以得到下一个可用的文件号,此后对文件的访问基于该文件号。 可执行以下操作: • Input:从文件中读取字符 • Output:向文件输出字符,文件原来的内容丢失 • Append:将字符追加到文件的最后,原内容保留 Input操作的前提条件是文件必须存在; Output和Append则可以自动先创建再打开。
读取顺序文件 • Input()函数,读取任意数量的字符到变量中 Text1.Text = Input(LOF(filenum), filenum) 第一个参数指读取字符数量,第二个参数指定文件号 • Input#语句,从文件中读取数据到一个或多个变量中,必须是指定格式或由Write#语句写入的数据 Input #1, MyName, MyNumber • LineInput#语句, 从文件中读取一行,给字符串变量 Line Input #filenum, LineString Text1.Text = Text1.Text + LineString+Chr(13) + Chr(10)
从文件中读取一行 • 【例】读取文件test.txt,结果置于一个文本框中。 Open "d:\test.txt" For Input As 1 Do Until EOF(1) Line Input #1, NextLine Text1.Text = Text1.Text + NextLine + vbCrLf Loop Close #1 • 尽管Line Input # 到达回车换行时它会识别行尾,但是,当它把整行字符串读入变量时,不会包括回车换行。如果要保留该回车换行,必须在代码中添加。
写入顺序文件 • Print#语句,向文件中写入一行 Print #filenumber, [outputlist] 第一个参数指定文件号, 第二个参数为表达式 Print #1, "This is a test" Print #1, ‘写入一个空行 Print #1, StuNum; Tab; StuName Print #1, Spc(5) ; "Hello" Print #1, Tab(10) ; "Hello" • Write#语句, 将数据写入文件(区别数据类型) Write #filenumber, [outputlist] Write #1, “Hello World”, 234 Write #1, strName • 与Print的区别: • 值之间使用逗号分隔 • 字符串使用引号括起
修改顺序文件 • 对于顺序文件没有提供直接修改的方法,如果要修改一个文件的内容,一般的步骤是: • 1)以Input方式打开文件; • 2)读取文件的内容到某个变量中,关闭文件; • 3)修改变量的值; • 4)以Output方式打开文件; • 5)将变量值写入到文件中,关闭文件结束。
关闭顺序文件 • Close#语句 Close #1 ' 关闭1号文件 Close #1, #2, #4 ' 关闭1号、2号和4号文件 Close ' 关闭所有打开的文件 • 执行Close语句后,文件与其文件号之间的关联将终结,同样的文件号可以在后面的程序中继续使用。 • 当对文件进行写入操作时,只有使用了关闭命令,才会真正将缓冲区的文件内容写入到磁盘的文件中,同时所有与该文件相关联的缓冲区空间都被释放。
访问顺序文件示例1 • 【例】读取任意指定的文本文件,进行如下处理:删除一个段落中的所有硬回车,只保留段落与段落之间的回车符(假设:某一行的第一个字符前有四个半角空格,就代表一个段落的开始)。
访问顺序文件示例 Dim strLine As String ‘ 用于保存每次读出的一行文本 Dim fileNo As Integer ' 当前打开文件的文件号 Text1.Text = "" Text2.Text = "" fileNo = FreeFile ' 获取当前可用的文件号 Open “d:\a.txt” For Input As fileNo Do While Not EOF(fileNo) ' 按行循环读出文件内容 Line Input #fileNo, strLine Text1.Text = Text1.Text & strLine & vbCrLf If Left(strLine, 4) = " " Then ' 行前有四个空格 Text2.Text = Text2.Text & vbCrLf & strLine Else Text2.Text = Text2.Text & strLine End If Loop Close #fileNo
访问顺序文件示例 ' 将处理后的文本写入文件 Open “d:\a.txt” For Output As fileNo Print #fileNo, Text2.Text Close #fileNo
访问顺序文件示例2 • 【例】将两个文本文件进行合并。如:1.txt + 2.txt -> 3.txt Dim f_in As Integer, f_out As Integer, str As String f_out = FreeFile() '打开合并后的文件用于写 Open App.Path & "\all.txt" For Output As f_out '打开第一个文件用于读,并写入到合并文件中 f_in = FreeFile() Open App.Path & "\1.txt" For Input As f_in Do While Not EOF(f_in) Line Input #f_in, str Print #f_out, str Loop Close #f_in '打开第二个文件用于读,并写入到合并文件中 Open App.Path & "\2.txt" For Input As f_in Do While Not EOF(f_in) Line Input #f_in, str Print #f_out, str Loop Close #f_in Close #f_out MsgBox "完成!"
访问顺序文件示例3 • 【例】进行全班考试成绩统计,计算平均分、最高分、最低分。成绩存放在score.txt文件中(以空格分开)。 Dim f1 As Integer, i As Integer, num As Integer, score(50) As Integer Dim str As String, strArray() As String num = 0 ‘计数,统计成绩个数 ‘打开分数文件,逐行读取并转换到数组中 f1 = FreeFile() Open App.Path & "\score.txt" For Input As f1 Do While Not EOF(f1) Line Input #f1, str ‘每行按照空格切分字符串, 切分结果在字符串数组strArray中 strArray = Split(str, " ") '全部分数转换后存放到score数组中 For i = 0 To UBound(strArray) score(num) = CInt(strArray(i)) num = num + 1 Next Loop Close f1
访问顺序文件示例3 min = 100 max = 0 For i = 0 To num - 1 sum = sum + score(i) If score(i) > max Then max = score(i) If score(i) < min Then min = score(i) '求各分数段人数 If score(i) < 60 Then c1 = c1 + 1 ElseIf score(i) < 70 Then c2 = c2 + 1 ElseIf score(i) < 80 Then c3 = c3 + 1 ElseIf score(i) < 90 Then c4 = c4 + 1 Else c5 = c5 + 1 End If Next avg = sum / num
文件长度和中文字符* • 获取文件长度 • 文件打开时:LOF(filenumber),如:LOF(1) • 文件没有打开是:FileLen(filename),如:FileLen(“c:\a.txt”) • 文件长度:返回的是文件中字节的个数,而不是字符个数 • 英文单字节编码系统(ANSI):一个字符就是一个字节 • 中英文混合编码系统(DBCS):中文两个字节,英文一个字节 • 统一双字节编码系统(Unicode):每个字符都占用两个字节,VB所有内部操作以此为基础 • 但是目前的文本文件基本上是采用DBCS。VB根据长度读取文件时,有两种方式: • Input(20, 1):这是按照字符的个数读取,然后自动转换为Unicode。 • InputB(20, 1):按字节的个数读取,不转换为Unicode(需要用StrConv函数) • 同样,字符串长度有两种方式: • Len(“你好Hello”) 结果是7(字符的个数) • LenB (“你好Hello”) 结果是14(字节的个数)
访问随机文件 • 随机文件由记录构成,每个记录由定长的字段构成,这样很容易随机找到某个记录的某个字段 • 随机文件中的字节构成相同的一些记录,每个记录包含一个或多个字段。 • 为了完整地定义随机文件中的记录,我们需要用户自定义类型。因为所有记录是同样的长度,所以所有字符串字段都必须使用定长字符串类型。例如,课程记录由三个字段组成的自定义类型Course来描述,每条记录的总长度为32个字节。 Type Course Name As String * 20 TeacherName As String * 10 ClassHours As Integer End Type
打开随机文件 • 随机文件打开后既可以写,同时又允许读,这和顺序文件每次打开只能执行某一种操作不同,这种优越性就是固定了每个记录的长度所带来的。 Open filename [For Random] As number Len = reclength • 表达式Len = reclength指定了记录的长度,每次读写操作以该长度为单位进行。一般指定reclength为自定义类型变量的长度,可利用Len函数取得 • 如果reclength比记录的实际长度短,则出错。比实际长度长,可写,但浪费了空间 Reclen = Len(Stu) Open file1 For Random As filenum len = Reclen RecCount = LOF(filenum) / Reclen
读取记录 Get filenumber, recnumber, varname • filenumber:打开的顺序文件的文件号 • recnumber:要读取的记录号,如省略则随上次记录向下 • varname: 读入的变量名 • 例如,将第10条记录取出,存放到变量Stu中: Get FileNum, 10, Stu
写入记录 Put [#]filenumber, [recnumber], varname • Recnumber:指定记录号。它是一个可选项,如果指定了记录号,就代表从指定的记录号所在位置开始写,如果省略则表示在上一个put语句紧邻的下一个记录位置开始写入,实质上记录号指定了记录写入文件的位置。 • Varname:记录变量,该变量数据将写入文件。 • 比如将变量myClass作为文件的第三个记录写入进去: myClass.Name = "VB程序设计" myClass.TeacherName = "张三" myClass.ClassHours = 40 Put #FileNum, 3, myClass
替换记录 • 替换随机文件中的记录,即修改记录原来的内容。替换操作不会改变文件的结构和长度。 • 仍然使用Put语句,如修改第10条记录的姓名字段: Get FileNum, 10, Stu Stu.Name = “Jonh” Put FileNum, 10, Stu
添加记录 • 在任何位置都可以添加新记录,即写入记录,而不论该位置之前是否存在非空记录。 • 如果需要紧邻上一记录,则只要保证记录号增1。设Reccount为原来的记录数: Reccount = Reccount + 1 Put FileNum, Reccount, Stu • LOF(filenumber):可以返回文件的大小,可以用于计算随机文件的记录个数: recCount = LOF(1) / recLength + 1
删除记录 • 删除记录会改变文件长度,以上简单操作无法完成。 • 需要使用一个临时文件,将原文件中的有效记录读取出来,写入到临时文件中,再将临时文件改名即可: • Get:使用Get语句从原文件中读记录 • Put:使用Put语句写部分记录到临时文件 • Kill:使用Kill语句删除原文件 • Name… As …:将临时文件换名为原文件名
访问随机文件示例 • 【例】编写程序,完成一个学期教学计划的安排,包括:从课程列表框中选择一门课程,从教师列表框选择任课教师,输入课时,然后添加到课程文件中。 • 为了提高灵活性,课程名和教师名存放在一个文本文件中,程序执行前,用户可以自行修改。
访问随机文件示例 ‘定义教学计划的记录类型 Private Type Course Name As String * 20 TeacherName As String * 10 ClassHours As Integer End Type ‘窗体加载事件中进行界面的初始化。首先初始化课时组合框 cboHours.AddItem "24" cboHours.AddItem "32" cboHours.AddItem "40" cboHours.AddItem "50" cboHours.AddItem "60" cboHours.ListIndex = 3
访问随机文件示例 Dim strLine As String ‘ 从课程文件中读取所有课程 Open App.Path & "\class.txt" For Input As 1 Do While Not EOF(1) Line Input #1, strLine lstClass.AddItem strLine Loop Close (1) lstClass.ListIndex = 0 ‘ 从教师文件中读取所有教师 Open App.Path & "\teacher.txt" For Input As 1 Do While Not EOF(1) Line Input #1, strLine lstTeacher.AddItem strLine Loop Close (1) lstTeacher.ListIndex = 0
访问随机文件示例 ' 添加课程信息到随机文件中 Private Sub cmdAdd_Click() Dim recNo As Integer Dim recLength As Integer Dim myCourse As Course myCourse.Name = lstClass.Text ' 准备要写入文件的变量 myCourse.TeacherName = lstTeacher.Text myCourse.ClassHours = CInt(cboHours.Text) recLength = Len(myCourse) ' 计算记录的长度 Open App.Path & "\course.dat" For Random As 1 Len = recLength recNo = LOF(1) / recLength + 1 ‘ 计算当前新记录的记录号 Put 1, recNo, myCourse Close (1) End Sub
访问二进制文件 • 二进制文件中的字节可以代表任何数据(如非定长记录格式)。只有精确地知道数据是如何写到文件中后,才可能对它进行正确的读取或检索,否则只能靠人工的猜测和推理。因此对于不想直接公开的内容,程序员通常会以二进制文件来保存。二进制访问需要了解每个字节代表的含义,只有掌握了文件格式后,才能编写程序正确地读出文件。 • 打开文件 Open filename For Binary As number • 读写文件 Get|Put number , recnumber, varname
文件系统的有关函数 • 与驱动器、目录和文件有关的操作,比如创建目录,复制、删除文件,文件改名等。这些函数不涉及文件内容的操作。 • 如何读出文件内容,或写一个文件以后再介绍。
改变当前驱动器 ChDrive drive • drive 必选参数,指定驱动器名, 为“”则不变 • drive 如果含多个字符, 则取第一个 例: ChDrive “D”
取当前目录 CurDir [(drive)] • drive:字符串表达式, 指定驱动器名 • 无参数, 或drive=“”, 返回当前驱动器路径 例: MyPath=CurDir MyPath=CurDir(“C”) MyPath=CurDir(“D”)
改变当前目录 ChDir path • path 必选参数,指定默认目录名, 可包含驱动器名 • 如果不指定驱动器, 则在当前驱动器上改变目录 例: ChDir “Vbbooks” ChDir “D:\Temp” 改变驱动器的默认目录, 但不改变默认驱动器
得到当前可执行文件路径 App.Path • App对象是一个全局对象, 不需要声明, 指定应用程序的有关信息 • Path, 返回应用程序执行文件路径 • Title, 返回应用程序在任务列表中的标题 • EXTName, 返回应用程序的执行文件名
建立和删除目录 MkDir path • path 必选参数,指定新目录名, 可包含驱动器名 • 如果不指定驱动器, 则在当前驱动器上建目录 RmDir path • 同上 例: MkDir “wxm” RmDir “D:\data” 删除目录, 必须是该目录是一个空目录, 没有文件
删除文件 Kill filename • filename 必选参数,指定文件名, 可包含路径 • filename 可以是包含通配符的字符串 例: Kill “D:\temp\test.dat” Kill “D:\temp\*.tmp” 删除文件, 必须是该文件没有正在使用
设置文件属性 SetAttr pathname, attributes • pathname 必选参数,指定文件名 • attributes 常数或数值表达式, 指定文件属性, 属性取值有:vbNormal, vbReadOnly, vbHidden, vbSystem, 例: SetAttr “D:\data.txt”, vbReadOnly + vbHidden 设置文件属性, 必须是该文件没有正在使用(打开) 读取文件属性,使用GetAttr(pathname)函数
文件拷贝 FileCopy source, destination Dim SourceFile, DestinationFile SourceFile = “名单.txt" DestinationFile = “名单2.txt“ FileCopy SourceFile, DestinationFile
文件改名 Name oldpathname As newpathname 重新命名文件并将其移动到一个不同的目录或文 件夹中。 • Name 可跨驱动器移动文件。 • Name 不能创建新文件、目录或文件夹 • 参数不能包括多字符(*) 和单字符 (?) 的统配符
DIR函数 返回指定参数条件的文件名或目录名 Dir[(pathname[, attributes])] • Pathname:目录名,可以含有通配符 • Attributes:文件属性 • vbNormal:0 • vbReadOnly:1只读 • vbHidden:2隐藏 • VbSystem:4系统 • vbVolume:8卷标 • vbDirectory:16包含目录
DIR函数 MyFile = Dir(“*.TXT”, vbHidden) ‘取第一个隐含TXT文件名 MyFile = Dir ‘取下一个 MyPath = “c:\” ‘取出C驱动器下所有一级目录名并显示 MyName = Dir(MyPath, vbDirectory) Do While MyName <> "" If MyName <> "." And MyName <> ".." Then If GetAttr(MyPath & MyName) = vbDirectory Then Debug.Print MyName End If MyName = Dir End If Loop
其它函数和语句 • FileDateTime(Filename):文件创建或最后修改日期和时间 • FileLen(Filename):返回打开前文件的长度(字节数 • FreeFile():返回一个可用的文件号 • EOF(filenumber):返回布尔值表明是否到达文件尾 • LOF(filenumber):返回文件的大小 • Loc(filenumber):返回文件当前的读/写位置 • Seek(filenumber):返回文件的当前位置 • Seek filenumber, position:设置文件的当前位置,影响下一次的读/写操作
使用对象类访问文件 • 虽然以上列出的一系列语句或函数可以全面操作驱动器、目录或文件,但它们很分散,难于记忆和使用。 • VB提供了一个完整的对象模型,该模型中包含了与驱动器、目录和文件等元素完全对应的一组对象,利用各个对象的属性和方法可以方便地获取文件系统的信息、处理目录和文件、以及读写顺序文件。 • 这就是File System Object(FSO)对象模型
File System Objects对象模型 FSO对象模型中主要的5个对象: • Drive对象:读取驱动器信息 • Folder对象:管理文件夹,读取文件夹信息 • Files对象:管理文件,读取文件信息 • TextStream对象:主要用于读写文件 • FileSystem Object对象:提供对驱动器、文件夹和文件的各种操作,核心对象。该对象建立在以上对象的基础之上,比如很多方法是复制了其它对象的方法,还提供方法创建生成以上对象。
使用类库(非可视化对象) • FSO对象不是一个可见的控件对象,不能通过部件添加到工程中,需要引用类库(Class Library) • 类库示对象类的集合,可以为开发者提供大量制作好的可以直接使用的对象 在工程中添加对象类引用 • “工程”菜单中,选择“引用”命令 • 选定类库名称左边的复选框 • 单击“确定”按钮
加载FSO对象模型 • FSO对象模型包含在一个称为Scripting的类型库中,此类型库位于Scrrun.Dll文件中。要使用该类型库,必须首先在工程中引用此文件,操作方法如下: • 执行【工程】→【引用】菜单命令,打开“引用”对话框; • 在对话框中的可引用类型库列表中选中“Microsoft Scripting Runtime”项并确定; • 使用“对象浏览器”可以查看其对象、集合、属性、方法、事件以及它的常数,同时在声明变量时,输入As关键字后,该类型库中的对象类型会自动显示在数据类型提示列表中。
FileSystemObject对象 该对象是FSO对象模型中的核心对象,FSO编程 的主要步骤: (1) 在“工程|引用”中选择“Microsoft Scripting runtime” (2) 创建一个FileSystemObject对象 (3)通过读取新对象的属性值获取信息 (4)调用FileSystemObject对象中的方法来创建一个新的对象,如Files对象、Drive对象
创建一个FileSystemObject对象 方法一:使用New关键字 Dim oFSO as FileSystemObject ‘声明对象 Set oFSO = New FileSystemObject ‘创建对象 或 Dim oFSO as New FileSystemObject ‘声明并创建对象 方法二:使用CreateObject函数 Dim oFSO as FileSystemObject ‘声明对象 Set oFSO=CreateObject(“Scripting.FileSystemObject”) 对象其实就象C语言中的指针,声明时并没有空间,也没有内容,是一个空值。只有创建后才能使用(等同于让指针指向一个有意义的空间)
访问驱动器 【例】窗体加载后,输出系统各驱动器的容量和剩余可用空间。 Private Sub Form_Load() Dim objFso As New FileSystemObject Dim strInfo As String, d On Error Resume Next For Each d In objFso.Drives strInfo = d.DriveLetter & " : " strInfo = strInfo & " 全部空间=" & d.TotalSize strInfo = strInfo & " 可用空间=" & d.AvailableSpace Debug.Print strInfo Next End Sub
FileSystemObject对象的属性 Drives属性:是一个驱动器对象的集合,即Drive对象 的集合。 Drive对象的主要属性有: • AvailableSpace:驱动器上的可用空间 • DriveLetter:驱动器号(只读) • DriveType:驱动器类型 • FileSystem:文件系统的类型 • FreeSpace:可用空间 • VolumnName:卷标名 • IsReady:是否准备好
使用FileSystemObject访问驱动器 • DriveExist方法:返回真存在,否则不存在oFSO.DriveExists(“d”) (2) GetDrive方法:返回一个指定的Drive对象 set oDrive = oFSO.GetDrive(“c:”) (3) GetDriveName方法:从指定的路径名中返回驱动器名,但不检查是否存在 oFSO.GetDriveName(“d:\vb6”)