java进阶 ------ IO流

[本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020]

流的概念和基本分类:

  流的概念:

    流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据的源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流动一样”。

  流的分类:

   按数据方向分:输入流和输出流

    输入流:InputStream/Reader

   输出流:OutputStream/Writer

   按数据类型分:字节流和字符流

    字节流:InputSteam/OutputStream

   字符流:Reader/Writer

  字节流和字符流的区别:

    1. 字节流读取的时候,读到一个字节就返回一个字节。字符流使用了字节流读到了一个或多个字节(中文对应的字节是两个,UTF-8码表中是三个)时,先去查指定的编码表,将查到的字符返回。

   2. 字节流可以处理所有类型的数据,如图片,mp3等。而字符流只能处理字符数据。

   3. 字节流输入流都是以InputStream结尾,字节流输出流都是以OutputStream结尾,在InputStream或者OutputStream前面代表这个流的作用。字符流输入流都是以Reader结尾,字符流输出流都是以WriterStream结尾,相同与字节流前面也是代表这个流的作用。实际上字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的,但是字符流在操作时会用到缓冲区,是能过缓冲区来操作文件的。 

    注意,只要是算是纯文本数据,就要优先考虑使用字符流,除此之外,都要使用字节流了。

常用流:

  字节输入流:

   InputStream类为所有字节流的父类。

   三个基本的read()方法:

   int read(); // 从流里读出一个字节。不推荐使用。

   int read(byte[] b); //  将数据读入到字节数组中,并返回所读的字节数。

   int read(byte[] b,int off,int len); // off 从哪里开始读取,len读取多少字节。将输入流中off 位置处最多len个数据字节读入到字节数组中。

   其他的一些常用方法:

   void close();   //  关闭此输入流并释放与该流关联的所有的系统资源。

   int available(); //  返回不受阻塞地从此输入流读取的字节数。

   long skip(long n); // 跳过和放弃此输入流中的n个数据字节,该方法可能失效。

   boolean markSupported(); // 测试此输入流是否支持mark和reset方法。

   void mark(int n); // 在此输入流中标记当前的位置。

   void reset();  // 将此流重新定位到对此输入流最后调用mark方法时的位置。

  字节输出流: 

    OutputStream类是所有字节输出流的父类。

   三个基本的write()方法。

   void write(int n); // 将指定的字节写入到此输出流中。

   void write(byte[] b); // 将b.length个字节从指定的字节数组中写入此输出流中。

   void write(byte[] b,int off,int len); // 将指定字节数组中从偏移量off开始的len个字节写入到此输出流中。

   其他的一些常用方法:

   void close(); // 关闭此输出流并释放与此流有关的所有系统资源。

   void flush(); // 刷新此输出流并强制写出所有缓冲的输出字节。

  文件输入输出流:

    FileInputStream和FileOutputStream

   要构造一个FileInputStream,所关联的文件必须存在而且是可读的。如:

    FileInputStream fis = new FileInputStream("myfile.dat");

   要构造一个FileOutputStream,而输出文件如果已经存在,则它会被覆盖。如:

    FileOutputStream fos = new FileOutputStream("result.dat");

   如果要想以追加的方式写入文件,则需要一个参数,即:

    FileOutputStream fos = new FileOutputStream("result.dat",true); // 参数为true时,则表示输出时,以追加的方式;为false时,则同上。

  字符流:

    Reader和Writer是所有字符流的父类型。

    java技术使用Unicode来表示字符串和字符,而且提供的16位版本的流,以便用类似的方法处理字符。

  桥梁流: 

     InputStreamReader和OutputStreamWriter(字节流转化成字符流的桥转换器)

    这两个类不是用于直接输入输出的,他是将字节流转换成字符流的桥转换器,并可以指定编解码方式。

  逐行读写流:

     以上两个都是过滤流,需要用其他的节点流来作参数构造对象。

    BufferedReader的方法:String readLine(); // 当他的返回值是null时,就表示读取完毕了。 要注意,再写入时要注意写换行符,否则会出现阻塞。

    BufferedWriter的方法:newLine();这个方法会写出一个换行符。

  管道流:

     线程交互的时候使用。

    PipedInputStream/PipedOutputStream传送输出流可以转接到传送输入流,以创建通信管道。传送输出流是管道的发送端。通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的PipedInputStream读取。

    注意:管道输出流和管道输入流需要对接。

  数据流:

     DataInputStream和DataOutputStream;  通过流来读写Java基本类,注意DataInputStream和DataOutputStream的方法是成对的。支持直接输出输入各种数据类型。

    注意,使用这两个类时,需要注意写入的顺序和读取的顺序相同,否则会将没有分割写入的信息分割不正确而读取出错误的数据。

  对象流:

    ObjectInputStream和ObjectOutputStream(实现对象序列化)。 对象流是过滤流,需要节点流作参数来构造对象,用于直接把对象写入文件和从文件中读取对象。

   只有实现了Serializable接口的类型的对象才可以被读写,Serializable接口是个标记接口,其中没有定义方法。

   对象会序列化一个二进制代码,文件中保存对象的属性。

   writeObject(o),readObject()这两个是对象读写操作时用的方法。如:

   一个类中有其他类型的对象,那么,这个类实现了Serializable接口,在对象序列化时,也同样要求这个类中属性都能够对象序列化。

   注意:

    对于对象流的操作,在写对象时要一次写入完毕,如果使用追加模式写入,只会读取到上一次写入的对象,使用对象流写入 时,会先写入一个头部,然后写入数据,最后加上结束符号,如果使用追加方式写入的话,那就会在结束符号继续向下写入,但是在读取时只会读到结束符为止,以后再次写入的数据就会丢失。

    包名,类名和属性可以被序列化,方法和构造器不会被序列化的。

    静态属性不会被序列化的。

    属性会被递归序列化的,也就是一个类中有引用类型的属性,如果这个属性对应的类实现了Serializable接口,在对象序列化时,也同样会对这个类中的属性进行对象序列化。

   下面以一个例子来演示上述各种流的用法:

IODemo.java

package com.jesson.mianshi.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Reader;

import javax.sound.sampled.Line;

import org.w3c.dom.CDATASection;

public class IODemo {

	private final static String path = "./testRead.dat";
	private static FileInputStream fis;
	private static FileOutputStream fos;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 测试read方法 
		byteReadFun();
		// 测试write方法
		byteWriteFun();
		// 测试FileReader方法
		charReaderFun();
		// 测试桥梁流
		bridgeStream();
		// 测试逐行读写流
		bufferedFun();
		// 测试数据流
		dataStream();
		// 测试对象流
		objectStream();
		// 测试管道流
		pipeFun();
	}

	/**
	 * 字节输入流的三种read方法和其他的一些常用方法测试
	 */
	private static void byteReadFun() {
		try {

			/**
			 * 方式1,每次读取一字节,读取整个文件,可以看出效率很底
			 */
			fis = new FileInputStream(path);
			int readByte = fis.read();

			while (readByte != -1) {
				System.out.print(readByte);
				readByte = fis.read();
			}
			fis.close();

			System.out
					.println("\n-----------------------------------------------------------------------------------------");
			/**
			 * 方式2, 每次撷取指定大小字节到数组中,其中,数组的大小可以任意指定
			 */
			fis = new FileInputStream(path);
			byte[] b = new byte[100];
			while (fis.read(b) != -1) {
				for (int i = 0; i < b.length && b[i] != '\0'; i++) {
					System.out.print(b[i]);
				}
			}

			fis.close();
			System.out
					.println("\n-----------------------------------------------------------------------------------------");

			/**
			 * 方式3, 每次读取指定大小字节到数组中,并指定写入数组的初始位置和长度,其中,数组的大小可以任意指定
			 */
			fis = new FileInputStream(path);
			byte[] b1 = new byte[100];
			fis.read(b1, 0, 20);
			for (int i = 0; i < b1.length; i++)
				System.out.print(b1[i]);
			fis.close();
			System.out
					.println("\n-----------------------------------------------------------------------------------------");

			/**
			 * 测试skip,mark,rest方法的使用
			 */
			fis = new FileInputStream(path);

			fis.skip(9);
			int len = 10;
			while (len-- > 0) {

				System.out.print(fis.read());
			}
			// 测试是否支持mark和reset方法
			System.out.println("\n是否支持mark和reset:" + fis.markSupported());
			System.out
					.println("-----------------------------------------------------------------------------------------");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * 字节输出流的三种write方法和其他的一些常用的方法测试
	 */
	private static void byteWriteFun() {
		try {
			/**
			 * 方式1:将指定的字节写入此输出流
			 */
			fos = new FileOutputStream("./testWrite.dat");
			fos.write(20);

			/**
			 * 方式2:将指定的b.length个字节从指定的字节数组写入此输出流中
			 */
			String outString = "Hello world!";
			byte[] b = outString.getBytes();
			fos.write(b);

			/**
			 * 方式3:将指定字节数组中从偏移量off开始的len个字节写入此输出流中
			 */

			String outString2 = "Hello jesson!";
			byte[] b2 = outString2.getBytes();
			fos.write(b2, 4, 5);
			fos.close();

			/**
			 * 方式4:如果想以追加的方式写入同一个文件,则需要一个参数,并且默认为false,即以覆盖的方式添加
			 */
			fos = new FileOutputStream("./testWrite.dat");
			fos.write(200);
			fos.flush(); // 刷新此输出流并强制写出所有缓冲的输出字节
			fos.close(); // 关闭此输出流并释放与此流有关的的有系统资源

			fos = new FileOutputStream("./testWrite.dat", true);
			String outString3 = "Hello java!";
			fos.write(outString3.getBytes());
			fos.flush();
			fos.close();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 字符输入输出流测试
	 */
	private static void charReaderFun() {
		try {
			FileWriter fWriter = new FileWriter("./testWriter.dat");
			fWriter.write("Hello,java,hello io!\n");
			fWriter.close();

			FileReader fileReader = new FileReader("./testWriter.dat");
			char[] cbuf = new char[50];
			int len = fileReader.read(cbuf);
			System.out.println(new String(cbuf, 0, len));

			fileReader.close();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out
				.println("-----------------------------------------------------------------------------------------");
	}

	/**
	 * 桥梁流,即 InputStreamReader和OutputStreamWriter
	 */
	private static void bridgeStream() {

		try {
			fis = new FileInputStream(path);
			InputStreamReader isr = new InputStreamReader(fis);
			char[] cbuf = new char[100];
			isr.read(cbuf);
			System.out.println(cbuf);
			isr.close();
			fis.close();

			fos = new FileOutputStream("./testWrite.dat");
			OutputStreamWriter osw = new OutputStreamWriter(fos);
			osw.write("good night!\n");
			osw.close();
			fos.close();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out
				.println("-----------------------------------------------------------------------------------------");
	}

	/**
	 * 逐行读写流:BufferedReader和BufferedWriter
	 */
	private static void bufferedFun() {

		try {
			FileWriter fWriter = new FileWriter("./testWriter1.dat");
			BufferedWriter bWriter = new BufferedWriter(fWriter);
			bWriter.write("我好,这个是逐行读写流");
			bWriter.newLine();
			bWriter.write("BufferedWriter");
			bWriter.newLine();
			bWriter.close();
			fWriter.close();

			FileReader fReader = new FileReader("./testWriter1.dat");
			BufferedReader bReader = new BufferedReader(fReader);
			String line = bReader.readLine();
			while (line != null) {
				System.out.println(line);
				line = bReader.readLine();
			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out
				.println("-----------------------------------------------------------------------------------------");
	}

	/**
	 * 测试管道流,主要是用于线程交互时
	 */
	private static void pipeFun() {
		System.out.println("管道流测试");
		try {
			PipedInputStream pis = new PipedInputStream();
			PipedOutputStream pos = new PipedOutputStream();
			pis.connect(pos);

			new Thread(new ReadThread(pis)).start();
			new Thread(new WriteThread(pos)).start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * 读线程 
	 *
	 * @author jesson
	 *
	 */
	static class ReadThread implements Runnable {
		PipedInputStream pis;

		public ReadThread(PipedInputStream pis) {
			// TODO Auto-generated constructor stub
			this.pis = pis;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				byte[] buf = new byte[1024];
				System.out.println("读取前......没有数据......阻塞");
				int len = pis.read(buf);
				System.out.println("读到数据......阻塞结束");
				String s = new String(buf, 0, len);
				System.out.println(s);
				pis.close();
			} catch (IOException e) {
				throw new RuntimeException("管道读取流失败");
			}
			System.out
					.println("-----------------------------------------------------------------------------------------");
		}

	}

	/**
	 * 写线程
	 *
	 * @author jesson
	 *
	 */
	static class WriteThread implements Runnable {
		PipedOutputStream pos;

		public WriteThread(PipedOutputStream pos) {
			// TODO Auto-generated constructor stub
			this.pos = pos;
		}

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				System.out.println("开始写入数据,等待6秒后.");
				Thread.sleep(6000);
				pos.write("hello pipeStream!\n".getBytes());
				pos.close();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

	/**
	 * 测试数据流
	 */
	private static void dataStream() {

		Member[] members = { new Member("jesson", 24),
				new Member("cherry", 23), new Member("john", 32) };
		System.out.println("测试数据流");
		System.out.println("操作前的数据");
		// 输出还原后的数据
		for (Member member : members) {
			System.out.printf("%s\t%d\n", member.getName(), member.getAge());
		}
		try {
			DataOutputStream dos = new DataOutputStream(new FileOutputStream(
					"testDataStream.txt"));

			for (Member member : members) {
				dos.writeUTF(member.getName());
				dos.writeInt(member.getAge());
			}
			// 将所有的数据写至目的地
			dos.flush();
			dos.close();

			DataInputStream dis = new DataInputStream(new FileInputStream(
					"testDataStream.txt"));
			for (int i = 0; i < members.length; i++) {
				String name = dis.readUTF();
				int age = dis.readInt();
				members[i] = new Member(name, age);
			}
			dis.close();
			System.out.println("还原后的数据");
			// 输出还原后的数据
			for (Member member : members) {
				System.out
						.printf("%s\t%d\n", member.getName(), member.getAge());
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out
				.println("-----------------------------------------------------------------------------------------");

	}

	/**
	 * 测试对象流
	 */
	private static void objectStream() {
		System.out.println("测试对象流");
		try {
			ObjectOutputStream oos = new ObjectOutputStream(
					new FileOutputStream("testObject.txt"));

			Object object = new Student("张三", 25, "西电");
			oos.writeObject(object);

			oos.close();

			ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
					"testObject.txt"));
			Student student = (Student) ois.readObject();

			ois.close();

			System.out.println(student.getName() + "\t" + student.getAge()
					+ "\t" + student.getSchool());

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out
				.println("-----------------------------------------------------------------------------------------");

	}

}

  在测试数据流时,用到了Member类,现给出Member.java

Member.java

package com.jesson.mianshi.io;

public class Member {
	private String name;
	private int age;

	public Member() {
		// TODO Auto-generated constructor stub
	}

	public Member(String name,int age){
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

  在测试对象流时,用到了实现序列化的类

Student.java

package com.jesson.mianshi.io;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/***
 * 序列化该类,用于传输保存等
 * @author jesson
 *
 */
public class Student implements Serializable{
	private String name;
	private int age;
	private String school;

	public Student() {
		// TODO Auto-generated constructor stub
	}

	public Student(String name,int age,String school){
		this.name = name;
		this.age = age;
		this.school = school;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSchool() {
		return school;
	}

	public void setSchool(String school) {
		this.school = school;
	}

	/**
	 * 定义writeObject方法,将对象写入流中,用于实现对象的持久化
	 * @param out
	 */
	private void writeObject(ObjectOutputStream out){
		try {
			out.writeUTF(name);
			out.writeInt(age);
			out.writeUTF(school);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 定义readObject方法,用于从流中读取对象
	 * @param in
	 */
	private void readObject(ObjectInputStream in){
		try {
			name = in.readUTF();
			age = in.readInt();
			school = in.readUTF();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

       

时间: 2024-10-16 03:39:13

java进阶 ------ IO流的相关文章

JAVA进阶-IO流(1)

http://download.csdn.net/detail/qq285016127/7963747 Java对文件的操作API一般分为字节流 字符流 其为文件的读写API框架也是通过这个思想去扩展的.另外,在流的流向中也分为源流和宿流.如图(流的主体是根据流向决定,如输入InputStream/输出流OutPutStream) <1>从整个框架上看,io流的主要知识点分为: 1.字节流(输入FileInputStream/输出FileOutputStream) 1)字节流的构造一般都会通过

JAVA进阶-IO流(2)

<2>以下介绍一些7.0中比较高级的io流. 5.DirectoryStream根据给定路径列举当前文件 1)Files.newDirectoryStream(path,".*");第2个参数指定搜索的文件格式 /** * 列举目录/文件 * * @author Lean @date:2014-9-22 */ public class DirListing { public static void main(String[] args) { listDir("E:

java常用IO流数据流小结

  类名 常用方法 说明 输入流 InputStream int read(); 只能读字节流,虽然返回值是int,但只有低8位起作用. DataInputStream Type readType(); 可以读二进制流,可以读byte,short,int,long,double等二进制流. BufferedReader String readLine(); 可以读文本行. 输出流 OutputStream void write(int); 只能写字节流,虽然形参是int,但只有低8为起作用. D

【Java】IO流简单分辨

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/5827509.html Java的IO流体系十分庞大,并且体系层次稍复杂,很容易记混或记错.在此,我把平时经常用到的几个流类的简易区分以及体系层次整理出来,方便记忆与辨析.本人对IO了解尚浅,文章如有错漏,恳请前辈指正,感激不尽! 字节流体系: 基类:InputStream/outputStream(抽象类,不能new) 子类: 文件IO字节流:FileInputStream/FileoutputStream

JAVA中IO流总结

本文是在学习中的总结,欢迎转载但请注明出处:http://write.blog.csdn.net/postedit/42119261 我想你对JAVA的IO流有所了解,平时使用的也比较的多,但是对于其具体分类和继承体系可能知道的并不多,可能也很少去看相关的API文档,找出其中的关系和各自的应用情形.本文简单对常用的IO流进行分类整理,并简单举例说明其应用.希望本文对你有所帮助. (A)IO流大致分为两种: (1)字节流:对应抽象类为InputStream(输入流)和 OutputStream(输

【JAVA的 IO流之FileInputStream和FileOutputStream】

java的 IO流即输入输出流,流是一组有顺序的,有起点和终点的字节结合,是对数据传输的总称.即数据在两设备间的传输称为流,流的本质是数据传输. IO流可以分为字节流和字符流.给出相应的IO结构图: 在接下来的一段时间里,将会慢慢介绍各种流的使用,本篇博客先介绍字节流的FileOutputStream和相对应的FileInputStream. 一.FileOutputStream(文件输出流) OutputStream是一个抽象类,抽象类必须通过子类实现.现在要向文件里输出就要用FileOutp

java的IO流,字节流和字符流

java操作文件都是通过流来处理的,(其实其他很多语言也是这样) 第一:java的IO流,分为:输入流 和 输出流(这真是废话,这是从流向的角度来说的) 第二:java的所有IO流,只分为:字节流 和 字符流(其实就是传输的颗粒,传输的基本单位) 总结:凡是处理纯文本的优先考虑字符流:其他的才考虑使用字节流

Java之IO流---字节流

1.1 IO流的引入 IO流在很多语言已有体现,诸如C语言的stdio.h,C++中的iostream.Java中的IO流大抵是用于在控制台.磁盘.内存上进行数据的读写操作,完成数据的传递. 我们可以对它进行如下分类: 按处理的数据类型可分为字节流与字符流 按流的流向可分为输入流(in)与输出流(out) 按流的功能可分为节点流(Node)和过滤流(Filter) 本篇侧重于梳理字节流相关的知识,毕竟作为字符流的前辈,它还是非常重要的.下篇继续梳理字符流. 1.2 IO流的继承体系图 大概描述了

Java笔记-IO流的运用

1.InputStream和System.in(Scanner) InputStream 输出流以字节为单位来获取数据,且需要复杂的判断并创建字节数组作为缓冲 另外字节转换为字符时容易出现中文乱码的情况:Scanner Java扫描器类,可以从输入流中读取指定类型的数据或字符串. 对于字符数据的读取,应该使用Scanner扫描器进行封装,然后获取字符串类型的数据 2. out和err out和err是System类的两个static类成员变量: out:主要是输出调试信息的输出流,以黑色显示 e