java io.docx

上传人:b****8 文档编号:9133721 上传时间:2023-02-03 格式:DOCX 页数:45 大小:83.85KB
下载 相关 举报
java io.docx_第1页
第1页 / 共45页
java io.docx_第2页
第2页 / 共45页
java io.docx_第3页
第3页 / 共45页
java io.docx_第4页
第4页 / 共45页
java io.docx_第5页
第5页 / 共45页
点击查看更多>>
下载资源
资源描述

java io.docx

《java io.docx》由会员分享,可在线阅读,更多相关《java io.docx(45页珍藏版)》请在冰豆网上搜索。

java io.docx

javaio

IO输入/输出

输入/输出(Input/Output)泛指对某个设备或环境进行数据的输入或输出。

例如对硬盘进行输入/输出、对视频设备进行输入/输出、对网络主机进行输入/输出等,可以想象,因设备或环境的不同,会有各式各样的输入/输出问题与解决方案。

输入/输出问题在程序设计中实际上是一个很复杂的问题。

对于输入/输出问题,Java将之抽象化为流(Stream)对象来解决。

对不同的输入/输出问题,会有相应的流对象提供解决的方案。

本章就是要学习Java中各式各样解决输入/输出问题的对象。

然而输入/输出问题所涉及的领域相当广,基于学习的角度来看,必须选择一个主题来专门讨论,所以本章主题会围绕在文件输入/输出。

有了本章的基础,在了解其他领域的输入/输出问题时就不难入手。

14.1.1 File类

不同的操作系统对于文件系统路径的设置各有差别。

例如在Windows中,一个路径的表示法可能是:

"C:

\\Workspace\\CH14\\"

而在Linux下的路径设置可能会像是:

"/home/justin/workspace/ch14"

Windows的路径指定是使用UNC(UniversalNamingConvention)路径名,以\\开始表示硬盘根目录。

如果没有以\\开始表示相对于当前工作目录的路径,C是可选的硬盘指定,后面跟随着:

字符。

而UNIX-Like系统没有Windows系统的C、D、E这样的硬盘驱动器概念,UNIX-Like系统的路径指定以/开始表示从根目录开始的绝对路径,不以/开始表示相对于当前工作目录的路径。

在程序中设置路径时会有系统相依性的问题,java.io.File类提供一个抽象的、与系统独立的路径表示。

给它一个路径字符串,它会将其转换为与系统无关的抽象路径表示,这个路径可以指向一个文件、目录或是URI(UniformResourceIdentifier)。

一个File的实例被建立时,它就不能再被改变内容。

File实例除了用作一个文件或目录的抽象表示之外,它还提供了不少相关操作方法:

可以用它来对文件系统作一些查询与设置的动作。

要注意的是,不管是文件还是目录,在Java中都是以File的实例来表示。

范例14.1是一个设置与操作File实例的简单示范,可以指定查询某个目录下的所有文件与目录名称。

范例14.1 FileDemo.java

packageonlyfun.caterpillar;

importjava.io.*;

importjava.util.*;

publicclassFileDemo{

publicstaticvoidmain(String[]args){

try{

Filefile=newFile(args[0]);

if(file.isFile()){//是否为文件

System.out.println(args[0]+"文件");

System.out.print(

file.canRead()?

"可读":

"不可读");

System.out.print(

file.canWrite()?

"可写":

"不可写");

System.out.println(

file.length()+"字节");

}

else{

//列出所有的文件及目录

File[]files=file.listFiles();

ArrayListfileList=

newArrayList();

for(inti=0;i

//先列出目录

if(files[i].isDirectory()){//是否为目录

//取得路径名

System.out.println("["+

files[i].getPath()+"]");

}

else{

//文件先存入fileList,待会再列出

fileList.add(files[i]);

}

}

//列出文件

for(Filef:

fileList){

System.out.println(f.toString());

}

System.out.println();

}

}

catch(ArrayIndexOutOfBoundsExceptione){

System.out.println(

"using:

javaFileDemopathname");

}

}

}

执行结果:

javaonlyfun.caterpillar.FileDemoC:

\

[C:

\WINDOWS]

[C:

\workspace]

[C:

\DocumentsandSettings]

[C:

\ProgramFiles]

[C:

\SystemVolumeInformation]

C:

\pagefile.sys

C:

\A3N_A3L.10

C:

\bootfont.bin

C:

\ntldr

...略

这里先简单地介绍一下File类。

File类主要是文件的抽象代表,若要作文件输出/输入,必须配合其他相关类来使用。

接下来会配合各小节的内容并适时地使用File类。

 

14.1.2 RandomAccessFile类

在正式介绍如何使用Java的输入/输出相关类来进行文件存取前,先简单地通过使用java.io.RandomAccessFile来存取文件,以认识一些文件存取时所必须注意的概念与事项。

文件存取通常是循序的,每在文件中存取一次,文件的读取位置就会相对于目前的位置前进一次。

然而有时必须指定文件的某个区段进行读取或写入的动作,也就是进行随机存取(RandomAccess),即要能在文件中随意地移动读取位置。

这时可以使用RandomAccessFile,使用它的seek()方法来指定文件存取的位置,指定的单位是字节。

为了移动存取位置时的方便,通常在随机存取文件中会固定每一个数据的长度。

例如长度固定为每一个学生个人数据,Java中并没有直接的方法可以写入一个固定长度数据(像C/C++中的structure),所以在固定每一个长度方面必须自行设计。

范例14.2先设计一个学生数据的类。

范例14.2 Student.java

packageonlyfun.caterpillar;

publicclassStudent{

privateStringname;

privateintscore;

publicStudent(){

setName("noname");

}

publicStudent(Stringname,intscore){

setName(name);

this.score=score;

}

publicvoidsetName(Stringname){

StringBuilderbuilder=null;

if(name!

=null)

builder=newStringBuilder(name);

else

builder=newStringBuilder(15);

builder.setLength(15);//最长15字符

this.name=builder.toString();

}

publicvoidsetScore(intscore){

this.score=score;

}

publicStringgetName(){

returnname;

}

publicintgetScore(){

returnscore;

}

//每个数据固定写入34字节

publicstaticintsize(){

return34;

}

}

对于每一个学生数据的实例在写入文件时,会固定以34字节的长度写入,也就是15个字符(30字节)加上一个int整数的长度(4字节)。

范例14.2中是使用StringBuilder来固定字符长度,可以使用size()方法来取得长度信息。

范例14.3则示范了如何使用RandomAccessFile来写入文件,并可随机指定一个所想读出的数据。

范例14.3 RandomAccessFileDemo.java

packageonlyfun.caterpillar;

importjava.io.*;

importjava.util.*;

publicclassRandomAccessFileDemo{

publicstaticvoidmain(String[]args){

Student[]students={

newStudent("Justin",90),

newStudent("momor",95),

newStudent("Bush",88),

newStudent("caterpillar",84)};

try{

Filefile=newFile(args[0]);

//建立RandomAccessFile实例并以读写模式打开文件

RandomAccessFilerandomAccessFile=

newRandomAccessFile(file,"rw");

for(inti=0;i

//使用对应的write方法写入数据

randomAccessFile.writeChars(students[i].getName());

randomAccessFile.writeInt(students[i].getScore());

}

Scannerscanner=newScanner(System.in);

System.out.print("读取第几个数据?

");

intnum=scanner.nextInt();

//使用seek()方法操作存取位置

randomAccessFile.seek((num-1)*Student.size());

Studentstudent=newStudent();

//使用对应的read方法读出数据

student.setName(readName(randomAccessFile));

student.setScore(randomAccessFile.readInt());

System.out.println("姓名:

"+student.getName());

System.out.println("分数:

"+student.getScore());

//设置关闭文件

randomAccessFile.close();

}

catch(ArrayIndexOutOfBoundsExceptione){

System.out.println("请指定文件名称");

}

catch(IOExceptione){

e.printStackTrace();

}

}

privatestaticStringreadName(RandomAccessFilerandomAccessfile)

throwsIOException{

char[]name=newchar[15];

for(inti=0;i

name[i]=randomAccessfile.readChar();

//将空字符取代为空格符并返回

returnnewString(name).replace('\0','');

}

}

执行结果:

javaonlyfun.caterpillar.RandomAccessFileDemostudent.dat

读取第几个数据?

2

姓名:

momor

分数:

95

RandomAccessFile上的相关方法实现都在批注中说明了,可以看到读写文件时几个必要的流程:

打开文件并指定读写方式

在Java中,当实例化一个与文件相关的输入/输出类时,就会进行打开文件的动作。

在实例化的同时要指定文件是要以读出(r)、写入(w)或可读可写(rw)的方式打开,可以将文件看作是一个容器,要读出或写入数据都必须打开容器的瓶盖。

使用对应的写入方法

对文件进行写入,要使用对应的写入方法。

在Java中通常是write的名称作为开头,在低级的文件写入中,要写入某种类型的数据,就要使用对应该类型的方法,如writeInt()、writeChar()等。

使用对应的读出方法

对文件进行读出,要使用对应的读出方法。

在Java中通常是read的名称作为开头,在低级的文件读出中,要读出某种类型的数据,就要使用对应该类型的方法,如readInt()、readChar()等。

关闭文件

可以将文件看作是一个容器,要读出或写入数据都必须打开容器的瓶盖,而不进行读出或写入时,就要将瓶盖关闭。

对于某些文件存取对象来说,关闭文件的动作意味着将缓冲区(Buffer)的数据全部写入文件,如果不作关闭文件的动作,某些数据可能没有写入文件而遗失。

14.2 位流

计算机中的数据都是以0与1的方式来存储,如果要在两个装置之间进行数据的存取,当然也是以0与1位的方式来进行,Java将数据于目的地及来源之间的流动抽象化为一个流(Stream),而流当中流动的则是位数据。

14.2.1 InputStream和OutputStream

计算机中实际上数据的流动是通过电路,而上面流动的则是电流,电流的电位有低位与高位,即数字的0与1位。

从程序的观点来说,通常会将数据目的地(例如内存)与来源(例如文件)之间的数据流动抽象化为一个流(Stream),而其中流动的则是位数据,如图14-1所示。

 

图14-1 数据的流动抽象化为流的概念

在JavaSE中有两个类用来作流的抽象表示:

java.io.InputStream与java.io.OutputStream。

InputStream是所有表示位输入流的类之父类,它是一个抽象类,继承它的子类要重新定义其中所定义的抽象方法。

InputStream是从装置来源地读取数据的抽象表示,例如System中的标准输入流in对象就是一个InputStream类型的实例。

在Java程序开始之后,in流对象就会开启,目的是从标准输入装置中读取数据,这个装置通常是键盘或是用户定义的输入装置。

OutputStream是所有表示位输出流的类之父类,它是一个抽象类。

子类要重新定义其中所定义的抽象方法,OutputStream是用于将数据写入目的地的抽象表示。

例如System中的标准输出流对象out其类型是java.io.PrintStream,这个类是OutputStream的子类(java.io.FilterOutputStream继承OutputStream,PrintStream再继承FilterOutputStream)。

在程序开始之后,out流对象就会开启,可以通过out来将数据写至目的地装置,这个装置通常是屏幕显示或用户定义的输出装置。

范例14.4可以读取键盘输入流,in对象的read()方法一次读取一个字节的数据,读入的数据以int类型返回。

所以在使用out对象将数据显示出来时,就是10进制方式。

范例14.4 StreamDemo.java

packageonlyfun.caterpillar;

importjava.io.*;

publicclassStreamDemo{

publicstaticvoidmain(String[]args){

try{

System.out.print("输入字符:

");

System.out.println("输入字符十进制表示:

"+

System.in.read()); 

}

catch(IOExceptione){

e.printStackTrace();

}

}

}

执行结果:

输入字符:

A

输入字符十进制表示:

65

字符A输入后由标准输入流in读取,A的位表示以十进制来看就是65,这是A字符的编码(查查ASCII编码表就知道了)。

一般来说,很少直接实现InputStream或OutputStream上的方法,因为这些方法比较低级,通常会实现它们的子类。

这些子类上所定义的方法在进行输入/输出时更为方便。

14.2.2 FileInputStream和FileOutputStream

java.io.FileInputStream是InputStream的子类。

从开头File名称上就可以知道,FileInputStream与从指定的文件中读取数据至目的地有关。

而java.io.FileOutputStream是OutputStream的子类,顾名思义,FileOutputStream主要与从来源地写入数据至指定的文件中有关。

当建立一个FileInputStream或FileOutputStream的实例时,必须指定文件位置及文件名称,实例被建立时文件的流就会开启;而不使用流时,必须关闭文件流,以释放与流相依的系统资源,完成文件读/写的动作。

FileInputStream可以使用read()方法一次读入一个字节,并以int类型返回,或者是使用read()方法时读入至一个byte数组,byte数组的元素有多少个,就读入多少个字节。

在将整个文件读取完成或写入完毕的过程中,这么一个byte数组通常被当作缓冲区,因为这么一个byte数组通常扮演承接数据的中间角色。

范例14.5是使用FileInputStream与FileOutputStream的一个例子。

程序可以复制文件,它会先从来源文件读取数据至一个byte数组中,然后再将byte数组的数据写入目的文件。

范例14.5 FileStreamDemo.java

packageonlyfun.caterpillar;

importjava.io.*;

publicclassFileStreamDemo{

publicstaticvoidmain(String[]args){

try{

byte[]buffer=newbyte[1024];

//来源文件

FileInputStreamfileInputStream=

newFileInputStream(newFile(args[0]));

//目的文件

FileOutputStreamfileOutputStream=

newFileOutputStream(newFile(args[1]));

//available()可取得未读取的数据长度

System.out.println("复制文件:

"+

fileInputStream.available()+"字节");

while(true){

if(fileInputStream.available()<1024){

//剩余的数据比1024字节少

//一位一位读出再写入目的文件

intremain=-1;

while((remain=fileInputStream.read())

!

=-1){

fileOutputStream.write(remain);

}

break;

}

else{

//从来源文件读取数据至缓冲区

fileInputStream.read(buffer);

//将数组数据写入目的文件

fileOutputStream.write(buffer);

}

}

//关闭流

fileInputStream.close();

fileOutputStream.close();

System.out.println("复制完成");

}

catch(ArrayIndexOutOfBoundsExceptione){

System.out.println(

"using:

javaFileStreamDemosrcdes");

e.printStackTrace();

}

catch(IOExceptione){

e.printStackTrace();

}

}

}

程序中示范了两个read()方法,一个方法可以读入指定长度的数据至数组,另一个方法一次可以读入一个字节。

每次读取之后,读取的光标都会往前进,如果读不到数据则返回-1,使用available()方法获得还有多少字节可以读取。

除了使用File来建立FileInputStream、FileOutputStream的实例之外,也可以直接使用字符串指定路径来建立。

//来源文件

FileInputStreamfileInputStream=

newFileInputStream(args[0]);

//目的文件

FileOutputStreamfileOutputStream=

newFileOutputStream(args[1]);

在不使用文件流时,记得使用close()方法自行关闭流,以释放与流相依的系统资源。

一个执行的结果范例如下,它将FileDemo.java复制为FileDemo.txt:

javaonlyfun.caterpillar.FileStreamDemoFileDemo.javaFileDemo.txt

复制文件:

1723字节

复制完成

FileOutputStream默认会以新建文件的方式来开启流。

如果指定的文件名称已经存在,则原文件会被覆盖;如果想以附加的模式来写入文件,则可以在构建FileOutputStream实例时指定为附加模式。

例如:

FileOutputStreamfileOutputStream=

newFileOutputStream(args[1],true);

构建方法的第二个append参数如果设置为true,在开启流时如果文件不存在则会新建一个文件,如果文件存在就直接开启流,并将写入的数据附加至文件末端。

虽然我一向不喜欢使用过长的范例来作程序示范(也不喜欢看很长的范例),不过本章的范例与其他各章的比起来相对长了一些,我会在程序中多用注释解释程序的逻辑。

因为解释输入/输出操作最好的方式,是呈现一个具实用性的范例,本章的范例除了练习的作用之外,日后需要某些输入/输出功能时,也可以来参考看看如何实现。

14.2.3 BufferedInputStream和BufferedOutputStream

在介绍FileInputStream和FileOutputStream的例子中,使用了一个byte数组来作为数据读入的缓冲区,以文件存取为例,硬盘存取的速度远低于内存中的数据存取速度。

为了减少对硬盘的存取,通常从文件中一次读入一定长度的数据,而写入时也是一次写入一定长度的数据,这可以增加文件存取的效率。

java.io.B

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1