实验13流式输入输出与文件处理编程.docx
《实验13流式输入输出与文件处理编程.docx》由会员分享,可在线阅读,更多相关《实验13流式输入输出与文件处理编程.docx(14页珍藏版)》请在冰豆网上搜索。
![实验13流式输入输出与文件处理编程.docx](https://file1.bdocx.com/fileroot1/2022-11/22/46124f6b-7032-4f49-b2e6-7cccf982deec/46124f6b-7032-4f49-b2e6-7cccf982deec1.gif)
实验13流式输入输出与文件处理编程
实验13 流式输入输出与文件处理
13.1实验目的
(1)掌握字节流和字符流的特点和处理差异;
(2)掌握过滤流的使用;
(3)掌握File类的使用;
(4)掌握随机文件的使用。
(5)掌握对象系列化的概念以及访问文件时对象读写方法。
13.2知识要点
13.2.1 面向字节的输入/输出流
(1)类InputStream是面向字节的输入流的根。
其主要方法见表13-1。
表13-1类InputStream的方法
方法
功能
intread()
读一个字节
intread(byteb[])
读多个字节到字节数组
intread(byte[]b,intoff,intlen)
读指定长度的数据到字节数组,数据从字节数组的off处开始存放
Longskip(longn)
输入指针跳过n个字节
Voidmark()
在当前指针位置处做一标记
Voidreset()
将位置指针返回标记处
Voidclose()
关闭流
(2) 数据过滤流DataInputStream
该流实现DataInput接口,主要方法有:
readByte(),readBoolean()、readShort()、readChar()、readInt()、readLong()、readFloat()、readDouble()、readUTF()等。
(3)类OutputStream是面向字节输出流的根,其主要方法有:
● voidwrite(intb):
将参数b的低字节写入输出流
● voidwrite(byteb[]):
将字节数组全部写入输出流
● voidwrite(byteb[],intoffset,intlen):
将字节数组中从b[offset]开始处的len个字节写入至输出流。
(4)类DataOutputStream实现各种类型数据的输出处理,它实现了DataOutput接口,主要方法有:
writeByte(int)、writeBytes(String)、writeBoolean(boolean)、writeChars(String)、writeInt(int)、writeLong()、writeFloat(float)、writeDouble(double)、writeUTF(String)等。
13.2.2面向字符的输入与输出流
类Reader是面向字符的输入流的根,其提供的方法与InputStream类似,只是将基于Byte的参数改为基于Char。
类Writer是面向字符的输出流类的根,其提供的方法与OutputStream类似,只是将基于Byte的参数改为基于Char。
类InputStreamReader是一个特殊的流,用来将面向字节的数据流包装转换为面向字符的流。
常用于从键盘获取输入数据。
例如,从键盘输入一行字符串,可以用BufferedReader的readLine()方法,但在此前必须使用InputStreamReader将字节流转化为字符流。
BufferedReaderin=newBufferedReader(newInputStreamReader(System.in));
Stringx=in.readLine()
13.2.3 文件的顺序读写
(1)面向字节的文件访问
● 以二进制文件作为数据源。
FileInputStream类和FileOutputStream类分别用于文件的读、写访问。
● 利用InputStream和OutputStream的方法可实现文件的读写操作。
● 可用DataInputStream对FileInputStream流进行过滤;用DataOuputStream对FileOutputStream流进行过滤,以实现特定数据类型数据的读写。
(2)面向字符的文件访问
● 以字符文件作为数据源。
包括:
FileReader类和FileWriter类分别用于字符文件的读、写访问。
● 基于字符流的数据读写方法与基于字节流的类似,只是将读写的单位由字节改为字符,方法中的字节数组参数相应改为字符数组。
例如:
intread(charb[])表示从文件读数据填满数组,返回读到的字符数。
● 可用BufferedReader对FileReader流进行过滤;用BufferedWriter对FileWriter流进行过滤,其中包含newLine()方法可写入一个换行。
13.2.4 File类
借助File对象,可以获取文件和相关目录的属性信息。
其主要方法见表13-2。
表13-2File类的主要方法
方法
功能
StringgetName()
返回文件名
StringgetPath()
返回文件或目录路径
StringgetAbsolutePath()
返回绝对路径
StringgetParent()
获取文件所在目录的父目录
booleanexists()
文件是否存在
booleancanWrite()
文件是否可写
booleancanRead()
文件是否可读
booleanisFile()
是否为一个正确定义的文件
booleanisDirectory()
是否为目录
LonglastModified()
文件的最后修改日期
Longlength()
文件长度
booleanmkdir()
创建当前目录的子目录
String[]list()
列出目录中的文件
booleanrenameTo(FilenewFile)
将文件改名为新文件名
Voiddelete()
删除文件
booleanequals(Filef)
比较两个文件或目录是否相等
13.2.5 随机文件
创建随机访问文件对象时要指定文件访问的“rw”参数,也就是它可以对同一打开文件进行读写两种访问。
RandomAccessFile类实现了DataInput和DataOutput接口,为支持流的随机读写,RandomAccessFile类还添加定义了如下方法:
● longgetFilePointer():
返回当前指针;
● voidseek(longpos):
将文件指针定位到一个绝对地址;
● longlength():
返回文件的长度
注意:
地址是相对于文件头的偏移量。
地址0表示文件的开头。
13.2.6 对象序列化
(1)对象输入流ObjectInputStream和对象输出流ObjectOutputStream将Java流系统扩充到能输入输出对象,它们提供的writeObject()和readObject()方法实现了对象的串行化(Serialized)和反串行化(Deserialized)。
(2)用对象输入流的readObject()方法必须捕捉ClassNotFoundException异常。
(3)为了实现用户自定义对象的串行化,相应的类必须实现Serializable接口,否则,不能以对象形式正确写入文件。
Serializable接口是一个不含任何具体内容的接口。
13.3样例程序
样例1:
编写一个程序实现任意文件的拷贝功能,源文件和目的文件名由命令行参数提供。
【参考程序】
importjava.io.*;
publicclassCopyFile{
publicstaticvoidmain(Stringargs[]){
if(args.length<2){
System.out.println("usage:
javaCopyFilesourcefiletargetfile");
System.exit(0);
}
byte[]b=newbyte[1024];
try{
FileInputStreaminfile=newFileInputStream(args[0]);
FileOutputStreamtargetfile=newFileOutputStream(args[1]);
while(true){
intbyteRead=infile.read(b);//从文件读数据给字节数组
if(byteRead==-1)//在文件尾,无数据可读
break; //退出循环
targetfile.write(b,0,byteRead); //将读到的数据写入目标文件
}
targetfile.close();
System.out.println("copysuccess!
");
}catch(IOExceptione){}
}
}
注:
本样例演示面向字节的输入输出流的进行文件读写的方法。
【编程技巧】
(1)创建一个字节数组存放从文件读取的数据;
(2)利用FileInputStream对象的带字节数组参数的read方法从文件读数据,返回读到的字节数;利用FileOutputStream对象的带字节数组的write方法可将字节数组中指定的字节写入到目标文件。
(3)利用循环控制文件的连续读写操作,在处理到文件结尾时,read方法返回-1,退出循环。
样例2:
编写一个程序统计一个文本文件中字符A的个数,文件名由命令行参数提供。
【参考程序】
importjava.io.*;
publicclassreadtxt{
staticStrings;
/* 方法find查找字符串in中A的个数*/
public static intfind(Stringin){
intn=0;
intcounter=0;
while(n!
=-1){
n=in.indexOf((int)'A',n+1);
counter++;
}
returncounter-1;
}
publicstaticvoidmain(String[]args){
try{
intn=0;
FileReaderfile=newFileReader(args[0]);
BufferedReaderin=newBufferedReader(file);
booleaneof=false;
while(!
eof) {
String x=in.readLine();//从文件读一行
if(x==null){ //判是否文件结束
eof=true;
}
else
s=s+x; //将内容拼接到字符串s上
}
System.out.print("thenumberofAis:
"+find(s));
in.close();
}catch(IOExceptione){};
}
}
注:
本样例演示文本文件的数据读取方法。
【编程技巧】
(1)循环利用BufferedReader的readLine()方法从文件读一行内容,读到文件尾部时将返回null;
(2)将读到的数据拼接到字符串s中,最后执行find方法找出A的个数。
样例3:
设计一个图形界面的文本文件查阅工具,在窗体中安排一个文本域和一个按钮(如图13-1所示),文本域用来显示文件的内容,点击打开按钮将弹出文件选择对话框(如图13-2所示),从而可以选择要查看的文件。
【参考程序】
importjava.awt.*;
importjava.awt.event.*;
importjava.io.*;
publicclassFileViewerextendsFrameimplementsActionListener{
Stringdirectory;//文件选择对话框的默认目录
TextAreatextarea;//显示文件内容的文本域
publicFileViewer(){this(null,null);}
publicFileViewer(Stringfilename){this(null,filename);}
publicFileViewer(Stringdirectory,Stringfilename){
addWindowListener(newWindowAdapter(){
publicvoidwindowClosing(WindowEvente){
dispose();
}
});
textarea=newTextArea("",24,80);
textarea.setFont(newFont("宋体",Font.PLAIN,12));
textarea.setEditable(false);
this.add("Center",textarea);
Panelp=newPanel();
p.setLayout(newFlowLayout(FlowLayout.RIGHT,10,5));
this.add(p,"South");
Buttonopenfile=newButton("OpenFile");
openfile.addActionListener(this);
openfile.setActionCommand("open");
openfile.setFont(newFont("SansSerif",Font.BOLD,14));
p.add(openfile);
this.pack();
//根据文件名路径得到目录,否则为系统当前目录.
if(directory==null){
Filef;
if((filename!
=null)&&(f=newFile(filename)).isAbsolute()){
//如果文件名中给出了绝对路径,则可根据创建的File对象得到文件的目录路径和文件名
directory=f.getParent();
filename=f.getName();
}
elsedirectory=System.getProperty("user.dir");//系统当前目录
}
this.directory=directory; //记住文件打开对话框的默认目录
setFile(directory,filename); //装载显示文件
}
/*从特定目录装载文件*/
publicvoidsetFile(Stringdirectory,Stringfilename){
if((filename==null)||(filename.length()==0))return;
Filef;
FileReaderin=null;
try{
f=newFile(directory,filename);//创建文件对象
in=newFileReader(f);//Andacharstreamtoreadit
char[]buffer=newchar[4096];//每次读4K字符
intlen;//每次读到的字符数
textarea.setText("");
while((len=in.read(buffer))!
=-1){
Strings=newString(buffer,0,len);
textarea.append(s);//读到的字符串添加到文本域
}
this.setTitle("FileViewer:
"+filename);//设置窗体标题
textarea.setCaretPosition(0);//将光标定到文本域的开头
}
catch(IOExceptione){
textarea.setText(e.getClass().getName()+":
"+e.getMessage());
this.setTitle("FileViewer:
"+filename+":
I/OException");
}
//任何情况下均要记住关闭流
finally{try{if(in!
=null)in.close();}catch(IOExceptione){}}
}
publicvoidactionPerformed(ActionEvente){
Stringcmd=e.getActionCommand();
if(cmd.equals("open")){
FileDialogf=newFileDialog(this,"OpenFile",FileDialog.LOAD);
f.setDirectory(directory);//设置文件打开对话框的默认目录
f.show();
directory=f.getDirectory(); //记住新的默认目录
setFile(directory,f.getFile());//装载显示文件
f.dispose();//得到文件后自动关闭对话框
}
}
publicstaticvoidmain(String[]args)throwsIOException{
Framef=newFileViewer((args.length==1)?
args[0]:
null);
f.addWindowListener(newWindowAdapter(){
publicvoidwindowClosed(WindowEvente){System.exit(0);}
});
f.setVisible(true);
}
}
注:
本样例演示File对象的使用以及读取文本文件数据的方法。
【编程技巧】
(1)如何利用File对象处理文件的目录和文件名,系统的当前目录如何得到;
(2)创建一个字符数组用于存放从文件读到的字符,利用FileReader的read方法可从文件读数据填入字符数组,无数据可读时返回-1,利用它作为循环控制标记;
(3) FileViewer构造方法的多态性编写,从而适应各种应用情形;
(4) FileDialog的使用,文件默认目录路径的设置和获取新默认路径的办法,新默认路径由对话框选择的路径决定。
13.4上机练习
✧ 基本题
1)编写一个程序将多个文件的内容合并为一个文件,被合并的文件的文件名由命令行参数输入。
例如:
javamergex1.txt x2.txt x3.txt x4.txt
2)从一个文本文件中读入30个学生的姓名和成绩,计算所有学生的最高分、最低分、平均分,将情况写入另一个文本文件中。
✧ 提高题
1)编写一个程序从一个文本文件中读入数据,统计其中不含重复的单词个数,并按单词出现频度有高到低输出。
2)编写应用程序实现图形的存储管理.
∙能实现直线和圆的绘制;
∙将绘制的图形以对象形式写入到文件中;
∙载入文件时能将图形绘制和修改,继续保存到文件中。
3)利用随机文件存储人员电话号码,编程支持如下功能:
查询某人的电话号码;增加、删除人员;修改人员电话号码。
13.5思考题
1)以下哪个是RandomAccessFile文件的构造方法:
A.RandomAccessFile("data","r");
B.RandomAccessFile("r","data");
C.RandomAccessFile("data","read");
D.RandomAccessFile("read","data");
2)设有如下代码:
importjava.io.*;
publicclassTh{
publicstaticvoidmain(Stringargv[]){
Tht=newTh();
t.amethod();
}
publicvoidamethod(){
try{
ioCall();
}catch(IOExceptionioe){}
}
}
以下哪个最有可能是ioCall方法的方法体?
A.publicvoidioCall()throwsIOException{
DataInputStreamdin=newDataInputStream(System.in);
din.readC