您的位置:首页 > 编程语言 > Java开发

java中的I/O处理

2016-06-30 21:33 417 查看

一.java中的I/O(一)

1.1 I/O操作的目标以及I/O的流向

I/O操作的目标是:从数据源当中读取数据,以及将数据写入到数据目的地当中。
I/O的流向

1.2 I/O的分类

分类的方法有三种:第一种分为输入流和输出流,第二种分为字节流和字符流,第三种分为节点流和处理流。
I/O中的核心类:字节流,每一种字节流都用类来表示。

核心类的核心方法:

inputStream:
int read(byte[]b,int off,int len)
/*
以byte类型的数组,从硬盘中读进的数据以字节形式,存放在byte类型的数组当中;
offset偏移量,假设offset=5,若读取的字节大小为1,此时存放在byte[]b,则需从b[5]开始;
一般情况下,offset=0,length为数组长度;
*/


OutputStream:
void write(byte[]b,int off,int len)


输出流中对于变量的定义和输入流中对于变量的定义是一样的。

1.3 读取文件和写入文件的方法

如何在一个文件中读取数据,再将数据写入到硬盘中的文件中去,需进行以下几个步骤:
a.InputStream,OutoutStream,FileinputStream,FileOutputStream属于I/O流中的包,需要将其导入。
b.需要写一个try......catch的结构,因为在I/O流中可能产生异常。
利用以下的代码来直观的理解一下输入流和输出流时如何来读取数据和写入数据的。

/*
第一步:导入类
第二步:inputstream,outputstream,Fileinputstream,Fileoutputstream都属于I/O流中的包;需要将其导入;
第三步:要写一个try......catch的结构,因为在处理i/o时可能产生异常;*/
import java.io.*;
public class Test {
public static void main(String[] args) {
int i ;
//声明输入流引用;
FileInputStream fis = null;
//声明输出流的引用;
FileOutputStream fos = null;
try{
//生成一个代表输入流的对象;
fis= new FileInputStream("D:/work/src/form.txt");//参数是你要打开的文件保存的位置 ;
//生成一个代表输出流的对象;
fos = new FileOutputStream("D:/work/src/to.txt");
byte[] buffer = new byte[100];//生成一个字节数组;
//调用输入流对象的read方法,读取数据;
int temp = fis.read(buffer,0 ,buffer.length);//若偏移量为5,此时会出现数组越界;解决办法是:buffer.length-5(5代表偏移量,buffer.length表示的是数组的最大长度)
fos.write(buffer,0,4);//定义一个临时变量来存放读取的文件字节大小,假设现在文本中存的是“abcd”此时字节大小为4,读进去多少就写入多少的数据;
for ( i = 0; i<buffer.length; i++){
System.out.println(buffer[i]);
}
//如何输出文本文档中的字节呢
/*String s = new String(buffer);
s= s.trim();//调用一个String对象的trim方法,将会去除掉这个字符首尾空格和空字符;
System.out.println(s);*/
}
catch(Exception e){
System.out.println(e);
}
}
}


总结一下:
a.I/O系统的主要目标是为了对数据进行读写操作,对于读的来源和写入目的地有多种。
b.数据的流向以Java程序作为参照物。
c.利用read和write方法来对数据进行读取和写入。

二.Java当中I/O(二)

2.1 大文件的读写方法

上面对于文件的读写,buffer的长度是固定的,文件大小是固定的。但是对于大文件来说,文件的大小是不固定的。因此不能采用上面的方法,将buffer的大小固定。

假设文件大小为1GB,则需对其进行循环读取。

/*第一步:导入类
第二步:inputstream,outputstream,Fileinputstream,Fileoutputstream都属于I/O流中的包;需要将其导入;
第三步:要写一个try......catch的结构,因为在处理i/o时可能产生异常;*/
import java.io.*;
public class Test1 {
public static void main(String[] args) {
	FileInputStream fis = null;//声明输入流引用;
	FileOutputStream fos = null;//声明输出流的引用;
try{
fis= new 	FileInputStream("D:/work/src/form.txt");//生成一个代表输入流的对象;参数是你要打开的文件保存的位置 ;
fos = new FileOutputStream("D:/work/src/to.txt");//生成一个代表输出流的对象;
//解决大文件的传输,需采用循环的方法;假设buffer的大小为1024字节,文件大小为4096字节,此时需要循环的读取四次,读取结束后,read的返回值为-1;
byte[] buffer = new byte[1024];//生成一个字节数组;buffer的大小是固定的,但是文件的大小是不固定的;
while(true){
int temp = fis.read(buffer,0 ,buffer.length);//调用输入流对象的read方法,读取数据;
if(temp==-1){
break;
}
fos.write(buffer,0,temp);//定义一个临时变量来存放读取的文件字节大小,假设现在文本中存的是“abcd”此时字节大小为4,读进去多少就写入多少的数据;
/*
fis.close();
fos.close();在这关闭输入流和输出流的话,是有问题的,假设在异常发生在try结构中,此时代码将直接跳到catch结构体中;若不发生异常,此时不执行catch结构体;为避免这种情况则采用finally结构;
*/
}
}
catch(Exception e){
	System.out.println(e);
}
finally{//在关闭输入流和输出流时,可能会出现异常,所以需要利用try......catch结构来处理;
try{
fis.close();
fos.close();
}
catch(Exception e){
System.out.println(e);
}
}
}
}


2.2 字节流的使用方法

字节流:读写文件是以字符为基础的。

import  java.io.*;
public class TestChar {
public static void main(String[] args) {
FileReader  fr = null;
FileWriter   fw = null;
try{
fr = new FileReader("D:/work/src/form.txt");
fw = new FileWriter("D:/work/src/to.txt");
char [] buffer = new char[1024];
while(true){
int temp = fr.read(buffer,0,buffer.length);
if(temp == -1){
break;
		}
/* for(int i = 0;i<buffer.length;i++){
System.out.println(buffer[i]);
		}*/
fw.write(buffer,0,temp);
}
}	  
catch(Exception   e){
System.out.println(e);
	 }
finally{
	try{
fr.close();
fw.close();
}
catch(Exception e ){
System.out.println(e);
}
 }
}
}


三Java中I/O(三)

3.1 处理流的使用实例

BufferedReader的使用方法是:前提是定义一个节点流,生成BufferedReader对象的方法

BufferedReader in = new BufferedReader(new FileReader"form.in")


在上面的定义中:new
BufferedReader是用来调用构造函数的,"form.in"是文件存放的位置,参数接收的是
new
FileReader对象。

/*
BufferedReader的使用方法:在使用处理流之前,首先会定义一个节点流 Filereader;
bufferedreader中的readLine方法并不是直接从文件中读取的,而是利用Bufferedreader中定义的参数filereader来读取数据;
将读取的数据利用readLine方法进行进一步的处理;
在装饰者模式中,Filereader是被装饰者,用来读取文件中的内容,而Bufferedreader是装饰者,它用来装饰Filereader,在此基础上添加新功能,意思是不仅仅可以读取文件中的内容;
Bufferedreader不仅可以装饰Filereader,只要是reader都可以,不仅可以实现文件的读取,还可以读取键盘输入的信息;
*/
import java.io.*;
public class Test {
public static void main(String[] args){
FileReader filereader= null;
BufferedReader bufferedreader = null;
try{
filereader = new FileReader("D:/work/src/form.txt");//在使用处理流bufferedreader时,首先要定义一个节点流Filereader;
bufferedreader = new BufferedReader(filereader);//此时里面的参数不是文件存放的位置,而是filereader这个对象;
/* String line = bufferedreader.readLine();//用来打印输出filereader文件中内容的第一行;
System.out.println(line);*/
String line= null;//利用readLine方法将文件中的所有内容全部打印输出;
while(true){
line = bufferedreader.readLine();
if( line == null){
break;
}
System.out.println(line);
}
}
catch(Exception e){
System.out.println(e);
}
finally{
try{
filereader.close();
bufferedreader.close();
}
catch(Exception e){
System.out.println(e);
}
}
}
}


需要说明的是bufferedreader中的readline方法并不是直接从文件中读取的,而是利用BufferedReader中定义的参数filereader来读取数据,将读取的数据利用readline方法进行进一步的处理。

3.2 JavaI/O的应用场景:装饰者模式

现在有一个需求:实现一个工人的管理系统,若使用继承,会出现一种问题,即创建的子类数目过多,为了简化继承体系使用装饰者模式。下图是利用继承实现一个工人的管理系统。

装饰者模式的简单示图:

AWorker中的doSomeWork(),在调用之前,先调用的是plumer中的doSomeWork(),plumer这个对象是可变的,无论怎样改变都是Worker这个接口的实例化。

/*会出现一种问题:就是水管工还要定义A,B公司的,木匠也是如此,一旦工种增加,就要创建许多的子类;
定义了一个接口,两个实现类;
Worker中有Plumer和CarPlenter,然后Plumer又有A,B公司的Plumer,这样会出现一种情况,使得继承变得越来越复杂;
不论现在出现哪种形式的工种,此时均是Worker接口的实例化,而AWorker只需要满足在传递参数的时候用的是Worker这个接口的实例化;
*/
public interface Worker {
public void doSomeWork();//接口中的方法为抽象方法;
 
}


public class Plumer implements Worker {//实现是一种特殊的继承;
public void doSomeWork(){
System.out.println("修水管");
}
}


 
public class CarPlenter  implements Worker {
public void doSomeWork(){
System.out.println("修门窗");
}
}


 
public  class AWorker implements Worker{
private Worker worker;//定义一个私有的Worker对象的引用worker;
//定义一个AWorker的构造函数,参数为Worker worker;
public AWorker(Worker worker){
//AWorker相当于装饰者,Worker相当于被装饰者
this.worker = worker;
}
 public void  doSomeWork(){
	 System.out.println("你好");//AWorker装饰者相当于在执行动作之前,添加一个额外的功能;
	 worker.doSomeWork();
}
}


/*
装饰者的设计模式:被装饰者所拥有的功能(假设水管工可以修水管) 那么装饰者就是在被装饰者的基础添加额外的功能,前提是在调用装饰者构造函数时参数必须是被装饰者的实例化对象;
*/
public class Test1 {
public static void main(String[] args) {
//生成一个A公司的水管工;
   Plumer plumer = new Plumer();
   //AWorker相当于Bufferedreader,plumer相当于Filereader;
   AWorker aWorker = new AWorker(plumer);//总的来说相当于是接口Worker中工种封装,此时AWorker调用的时候只需调用接口中的实例化对象即可,这样避免了工种再进行A,B 公司的划分;
   //Worker为父类对象,可以利用向上转型,将子类Plumer的对象赋值给父类的引用;
   aWorker.doSomeWork();//存在一个问题:AWorker这个对象是可变的?对于Worker中的实例化参数有所改变的话,那么此时在调用doSomeWork这个成员函数时:AWorkwer这个对象的引用也应发生相应的变化?
  
//若在此利用aworker的话,会出现和下面中的变量重复(AWorker相当于C语言中的变量类型,而后的变量是不能重复的);
 
CarPlenter carplenter = new CarPlenter();
   AWorker aworker = new AWorker(carplenter);//Worker为父类对象,可以利用向上转型,将子类CarPlenter的对象赋值给父类的引用;
   aworker.doSomeWork();
}
}


从上面的代码中可以简单理解装饰者模式是如何简化继承体系,使得继承更加简单高效。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: