java io.docx
- 文档编号:9133721
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:45
- 大小:83.85KB
java io.docx
《java io.docx》由会员分享,可在线阅读,更多相关《java io.docx(45页珍藏版)》请在冰豆网上搜索。
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();
ArrayList
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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java io