JAVA输入流和输出流

JAVA中的输入流和输出流是装载和运送信息的管道,管道一端接到信息来源,另一端连接信息的目的地。文中分别介绍输入(InputStream)和输出流(OutputStream)

       1、InputStream抽象类,是所有字节输入流的超类,直接继承Object,不能用构造器创建对象,只能通过子类创建对象。


                                                                字节输入流相关类的继承图

        2、FileInputStream类,文件输入流,构造器创建对象时要传入文件对象或文件路径,即把输入流信息源端接到文件上,可以把文件内容读取到流中。常用的方法是read()和read(byte[] b),前者是依次读取每个字节,后者一次性把信息读取到byte数组中。

  3、ByteArrayInputStream类,byte数组输入流,构造器参数是byte数组,与FileInputStream类似,把输入流的信息源端连接到byte数组上,读取byte数组中的内容。常用方法与FileInputStream相同。

       实例1,用FileInputStream/ByteArrayInputStream的两个方法读取信息。

InputStream is = new FileInputStream(File file)//ByteArrayInputStream(byte[] b);
//依次读取每个字节,read()
int i;
while((i=is.read())!=-1){
   System.out.println(i);//打印出读取内容
}
//一并读取到字节数组中,read(byte[])
byte[] b = new byte[is.available];
is.read(b);
String s = new String(b);//将字节数组转换成String
System.out.println(s);

        上述代码分别用read()和read(byte[] b)读取文件//字节数组,是最基础的实例.

 4、FilterInputStream,构造器是protected,故不能通过构造器创建对象,一般使

用其子类对象,嵌套在基本输入流(InputStream)上使用。

       5、BufferedInputStream类是FilterInputStream的子类,为添加了mark,reset功   能。创建对象时会创建一个内部缓冲区数组,在缓冲区中可以操作输入流的内容。

       6、DataInputStream类,FilterInputStream的子类,使用率非常高的输入流嵌套   这个高级管道后,输入流可以读取任何基本类型的数据,readInt()—读取4个字节组成Int返回。其他数据类型以此类推。

       7、ObjectInputStream类,InputStream的子类,重构序列化内容的输入流, 继承DataInput接口,和DataInputStream一样可以读取基本数据类型。另外Object obj = readObject();方法返回obj对象,即返回重构的序列化对象(要先知道序列化文件中对象存储顺序)。一般和ObjectOutputStream一起使用。不能读取普通输入的txt文件,因为ObjectInputStream读取文件要先读取一Header,会导致文件编码出错。(随后的ObjectOutputStream中有实例)

        8、 PipedInputStream类,必须要和PipedOutputStream类一同使用对接两个管道,Piped要在线程中使用,否则会造成单线程堵塞。连接的方法1,构造器中传入参数PipedInputStream pis = new PipedInputStream(PipedOutputStream pos),Out类与此相同,2,连接方法pis.connect(pos)或pos.connect(pis),其中pis和pos分别是PipedInputStream和PipedOutputStream的对象。需要注意的是不能重复连接,即构造器连接了就不要再用connect方法连接,不然会抛出异常。读取/写入方法分别是pis.read(byte[] b)和pos.write(byte[] b)。

  9、SequenceInputStream类,串联多个输入流,依次读取输入流中内容,构造器参数有两种(InputStream s1,InputStream s2)和(Enumeration<InputStream> e),前者连接两个输入流,后者连接多个输入流。需要特别注意的是,虽然Sequence类提供了read(byte[] b)方法,但是该方法每次只能读取一个InputStream中的内容,方法available()返回的是第一个InputStream内容长度。所以,在Sequence中,只能用read()方法依次读取每个字节,再拼接起来。

实例2:串联两个输入流

//SequenceInputStream串联两个输入流
public void SequenceInputStream(){
     try{	
	InputStream is = new FileInputStream(File file);//文件路径也可做参数	
	InputStream is1 = new FileInputStream(File file);
	SequenceInputStream sis = new SequenceInputStream(is,is1);
              //如果用sis.available结果与is.available相同
	     int len = is.available()+is1.available();
	     byte[] b = new byte[len];
	     int c = 0,count=0;
	     while((c=sis.read())!=-1){//依次读取每个字节,并存放在byte[]中
		  b[count] = (byte)c;
		  count++;
		}
		System.out.println("String是: "+new String(b));				
	  }catch(Exception e){e.printStackTrace();}	
	}

   实例3:串联多个输入流,只需对实例2稍作修改

//串联多个输入流
public static void SequenceEnumeration(){
	  try{
		Vector<InputStream> v = new Vector();
		v.addElement(new FileInputStream(File file);
		v.addElement(new FileInputStream(File file);
		v.addElement(new FileInputStream(File file);
		Enumeration<InputStream> e = v.elements();
		SequenceInputStream sis = new SequenceInputStream(e);
		int len=0;
		//长度仍需要依次累加
                for(int i=0;i<v.size();i++){
			len = len+ v.get(i).available();
		}
		byte[] b = new byte[len];
		int c = 0,count=0;
		while((c=sis.read())!=-1){
			b[count] = (byte)c;
			count++;
		}
		System.out.println("String是: "+new String(b));		
	  }catch(Exception e){e.printStackTrace();}
	}

 

       下面介绍输出流,有联合了对应输入流的实例

       1、OutputStream抽象类,是所有字节输出流的超类,有最基本的写入方法write(byte[] b),大多使用其子类。

                                                                             字节输出流相关类的继承图

         2、FileOutputStream类,文件输出流,将输出流中的内容输出到文件中,故构造器参数是文件对象或文件路径,构造器创建对象时就把流管道的输出端连到文件了。输出方法也是write(byte[] b)。但是,写入的文件路径不存在怎么办,路径存在恰好有同名文件夹怎么办?在附件FileOut.rar中有文件环境检测程序(很简单的程序)。

       3、ByteArrayOutputStream类,字节数组输出流,把流中的内容输出到字节数组中。一般与DataOutputStreamObjectOutputStream联合使用,作用就是把信息(基本数据类型或对象)转换成byte[],因为任何信息本质上说都是由字节组成,所以这样是返璞归真,把信息转化成了最本质的字节,信息经过传递,到另外一台主机上后,在用对应的输入流读取,还原信息原貌。

   ByteArrayInputStream和ByteArrayOutputStream处理信息流程图

   实例4:ByteArrayOutputStream和ObjectOutputStream的联合使用

   代码中用上述两个输出流把对象序列化,并转化成字节数组,在用对应的输入流重构被序列化的对象。

   节点对象代码如下:需要注意的是该节点对象必须连接Serializable接口,不然运行ObjectOutputStream会报错。

 

public class Node implements Serializable{
	private String name;//节点名
	private int weight;//权值
	private int d;//度

	public Node(String name,int weight,int d){
		this.name = name;
		this.weight = weight;
		this.d = d;
	}
	//get(),set()方法略
}
     主体代码:
public class ByteArrayOut{
    public static byte[] b;
    //创建一个ArrayList,里面放Node
    public static ArrayList<Node> getList(){
    	ArrayList<Node> list = new ArrayList<Node>();
    	for(int i=0;i<10;i++){
    		Node node = new Node("N"+i,i*2,i+3);
    		list.add(node);
    	}  	
    	return list;
    }   
    //把List中的Node对象放入输出流并转换成了byte[]
	public static byte[] WriteObj(){
	  try{	
		ArrayList<Node> list = getList();
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(os);
		   oos.writeInt(list.size());
		for(int i=0;i<list.size();i++){
		   oos.writeObject(list.get(i));
		}
		byte[] b = os.toByteArray();
		os.flush();
		os.close();
		System.out.println(b.length);
		return b;
	  }catch(Exception e){e.printStackTrace();}
	    return null;	 
	}
	
	public static void AyaByteArray(byte[] b){
	  try{	
		ByteArrayInputStream bis = new ByteArrayInputStream(b);
		ObjectInputStream ois = new ObjectInputStream(bis);
		int len = ois.readInt();
		System.out.println("读取出来的len:"+len);
		ArrayList<Node> li = new ArrayList<Node>();
		for(int i=0;i<len;i++){
			Node node = (Node)ois.readObject();
			li.add(node);
		}
		ois.close();
        //遍历list
		for(int i=0;i<li.size();i++){
			Node node = li.get(i);
			System.out.println("第"+i+"个node,name:"+node.getName()
					+" 度:"+node.getD()+" 权重"+node.getWeight());		
		}				
	  }catch(Exception ef){ef.printStackTrace();}
		
	}
	
	public static void main(String[] args){
		byte[] b = ByteArrayOut.WriteObj();
		ByteArrayOut.AyaByteArray(b);
	}
}
      上述实例完成了对象的序列化,把对象转化成一个一个的字节保存,随后又用保存的字节重构原对象,成功传递 对象

 

      4、FilterOutputStream,所有缓冲输出流的父类,构造器是protected,不能创建对象,一般嵌套基本输出流使用。

      5、BufferedOutputStream类,FilterOutputStream的子类,创建对象时提供缓冲区,要嵌套在基本输出流上使用。使用方法write(byte[] b)把字节数组的内容读到输出流的缓冲区。可以实现文件复制。

 

      6、DataOutputStream类,FilterOutputStream的子类,也要嵌套在基本数据流上使用,可以把JAVA中的基本数据类型写入输出流中,如writeInt(Int i),writeUTF(String str)分别将Int,String到写到输出流中,到网络另一端再用对应输入流读取。DataOutputStream经常和ByteArrayOutputStream联合使用,以字节数组形式储存并传输基本数据类型。

      7、ObjectOutputStream类,用特有的writeObj(Object obj)方法把对象读入输入流中,即序列化对象,将其保存。需要时调用ObjectInputStream重构被序列化的对象,与DataOutputStream相似,可以读基本数据类型到数据流。但对于方法writeBytes(String s),ObjectInputStream中没有对应的读取方法(只有readByte(byte b),没有readBytes()),所以使用writeBytes(String s)时要先写入字符串长度,再写入字符串,读取时readByte(byte b)依次读取每个自己,或用writeUTF(String s)方法写入,对应的readUTF(String s)读取。

 

     实例5:ObjectInputStream和ObjectOutputStream的写入和读取。

public class ObjectOut {

	public static void writeObject(){
	 try{	
                FileOutputStream fos = new FileOutputStream("C:\\obj.obj");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeInt(10);
		oos.writeUTF("UTF_str");
		Node node = new Node("name",12,12);
		oos.writeObject(node);
		oos.flush();
		oos.close();
		
	 }catch(Exception e){e.printStackTrace();}
	}
	
	public static void readObject(){
	 try{
		FileInputStream fis = new FileInputStream("C:\\obj.obj");
		ObjectInputStream ois = new ObjectInputStream(fis);
		int i = ois.readInt(); 
		String str1 = ois.readUTF();
		Node node = (Node)ois.readObject();
		System.out.println("int是:"+i+" str1是:"+str1);
		System.out.println("node的name:"+node.getName()
				+" 度:"+node.getD()+" 权重"+node.getWeight());
		 
	 }catch(Exception e){e.printStackTrace();}
	}
	
	public static void main(String[] args){
		ObjectOut.writeObject();
		ObjectOut.readObject();
	}
	
}
        8、 PipedOutputStream类,与PipedInputStream连接使用的专属类,构造器参数就是PipedInputStream。或者用方法connect()连接,不能多次连接。另外,Piped输入输出流绝大多数情况下用于多线程,一个线程写入信息,另一个线程读取。如果用单线程,则可能造成通道锁死。

 

     至此,JAVA中字节输入流和输出流经常使用的类介绍完毕。流是传输信息的管道,两端分别连接信息源和目的地,例如,需要读取文件中内容时,用FileInputStream从文件中把信息读出来就行了,需要写入信息到文件中时,就用FileOutputStream把信息写入文件。更多时候,把流管道的一端连接到网络,在网络另一端用对应流接收,就实现网络之间的信息传递。

     写得不好的地方,敬请批评指正。

 

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java IO学习总结 Java操作有关的类或接口: Java类图结构: 的概念和作用 是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为的本质是数据传输,根据数据传输特性将抽象为各种类,方便更直观的进行数据操作。 IO的分类 根据处理数据类型的不同分为:字符和字节 根据数据向不同分为:输入输出 字符和字节 字符的由来: 因为数据编码的不同,而有了对字符进行高效操作的对象。本质其实就是基于字节读取时,去查了指定的码表。 字节和字符的区别: 读写单位不同:字节以字节(8bit)为单位,字符以字符为单位,根据码表映射字符,一次可能读多个字节。 处理对象不同:字节能处理所有类型的数据(如图片、avi等),而字符只能处理字符类型的数据。 结论:只要是处理纯文本数据,就优先考虑使用字符。 除此之外都使用字节输入输出输入只能进行读操作,对输出只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的Java IO对象 1.输入字节InputStreamIO 中输入字节的继承图可见上图,可以看出: InputStream 是所有的输入字节的父类,它是一个抽象类。 ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。 ObjectInputStream 和所有FilterInputStream 的子类都是装饰(装饰器模式的主角)。 2.输出字节OutputStream IO 中输出字节的继承图可见上图,可以看出: OutputStream 是所有的输出字节的父类,它是一个抽象类。 ByteArrayOutputStream、FileOutputStream 是两种基本的介质,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据, ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰。 3.字节输入输出的对应 图中蓝色的为主要的对应部分,红色的部分就是不对应部分。紫色的虚线部分代表这些一般要搭配使用。从上面的图中可以看出Java IO 中的字节是极其对称的。“存在及合理”我们看看这些字节中不太对称的几个类吧! LineNumberInputStream 主要完成从中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入了。 PushbackInputStream 的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。 StringBufferInputStream 已经被Deprecated,本身就不应该出现在InputStream 部分,主要因为String 应该属于字符的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。 SequenceInputStream 可以认为是一个工具类,将两个或者多个输入当成一个输入依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构,却让其更“纯洁”――纯洁的Decorator 模式。 PrintStream 也可以认为是一个辅助工具。主要可以向其他输出,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例! 4.字符输入Reader 在上面的继承关系图中可以看出: Reader 是所有的输入字符的父类,它是一个抽象类。 CharReader、StringReader 是两种基本的介质,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。 BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。 FilterReader 是所有自定义具体装饰的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。 InputStreamReader 是一个连接字节和字符的桥梁,它将字节转变为字符。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。 5.字符输出Writer 在上面的关系图中可以看出: Writer 是所有的输出字符的父类,它是一个抽象类。 CharArrayWriter、StringWriter 是两种基本的介质,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据, BufferedWriter 是一个装饰器为Writer 提供缓冲功能。 PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。 OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用OutputStream 极其类似,后面会有它们的对应图。 6.字符输入输出的对应 7.字符与字节转换 转换的特点: 其是字符和字节之间的桥梁 可对读取到的字节数据经过指定编码转换成字符 可对读取到的字符数据经过指定编码转换成字节 何时使用转换? 当字节和字符之间有转换动作时; 操作的数据需要编码或解码时。 具体的对象体现: InputStreamReader:字节到字符的桥梁 OutputStreamWriter:字符到字节的桥梁 这两个对象是字符体系中的成员,它们有转换作用,本身又是字符,所以在构造的时候需要传入字节对象进来。 8.File类 File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 9.RandomAccessFile类 该对象并不是体系中的一员,其封装了字节,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点: 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw) 注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值