深入分析Java中的I/O类的特征及适用场合

Java中有40多个与输入输出有关的类,如果不理清它们之间的关系,就不能灵活地运用它们。

如果从流的流向来分,可分为输入流和输出流,而输入流和输出流又都可分为字节流和字符流。因而可将Java中的I/O流以下图进行划分:

注意上图并非继承关系,而只是一个示意图。

Java中的其它与I/O流处理相关的类其实都是从InputStream,Reader,OutputStream和Writer这4个基类继承而来。其中InputStream和OutputStream为字节流,Reader和Writer为字符流。

之所以这样划分,是因为计算机中所有的数据都是二进制的,而字节流可处理所有的二进制文件,但如果使用字节流来处理文本文件,也不是不可以,但是会更麻烦,所以通常有如下一个规则:如果进行输入/输出的内容是文本文件,则应该考虑使用字符流;如果进行输入/输出的内容是二进制内容(如图片、音频文件),则应该考虑使用字节流。

下面是从InputStream,Reader,OutputStream,Writer这4个基类出发,列出了常用的子类:

下面对各个类的特点及适用场合进行说明:

1.其中InputStreamReader和OutputStreamWriter是比较特殊的类,它们可将字节流转换为字符流,因而称为转换流。如InputStreamReader reader=new InputStreamReader(System.in);

2.BufferedInputStream,BufferedOutputStream的用法虽然和FileInputStream,FileOutputStream的用法一样,但是效率却相差很大,因为内存的效率比IO操作的效率要高得多,而BufferedInputStream,BufferedOutputStream会提前将文件中的内容读取(写入)到缓冲区,当读取(写入)时如果缓冲区存在就直接从缓冲区读,只有缓冲区不存在相应内容时才会读取(写入)新的数据到缓冲区,而且通常会请求的数据要多。所以在读取(写入)文件,特别是较大的文件时,不要用最简单的FileInputStream和FileOutputStream,而要考虑使用BufferedInputStream,BufferedOutputStream.

3.ObjectInputStream,ObjectOutputStream则分别是将序列化的对象(即实现了Serializable接口的对象)读取出来/写入到文件中,显然,这其实是利用反射的原理。

4.前面说过,Reader与InputStream的区别在于一个是字符输入流,一个是字节输入流。FileReader与FileInputStream对应,BufferedReader与BufferedInputStream对应,所以在读取文本文件时最好使用BufferedReader而不要使用FileReader.

由于ByteArrayInputStream及PipedInputStream不常用,本文暂不讨论。

下面是一些代码实例:

首先是比较原始的读取文件的方法,即采用FileInputStream:

//这是读取字节流的实例
public class FileInputStreamSample {

	public static void main(String[]args) throws IOException
	{
		FileInputStream fis=new FileInputStream("d://error.dat");
		byte[]buff=new byte[1024];
		int hasRead=0;
		while((hasRead=fis.read(buff))>0)
		{
			System.out.println(new String(buff,0,hasRead));
		}

		fis.close();

	}
}

然后是利用FileOutputStream进行文件的写入:

public class FileOutputStreamSample {

	public static void main(String[]args)
	{
		String fileName="d://error.dat";
		//注意:不必提前新建,因为如果没有新建的话,它自己会新建一个。
		String newFileName="d://error2.txt";
		try
		(FileInputStream fis=new FileInputStream(fileName);
		 FileOutputStream fos=new FileOutputStream(newFileName))
		 {
			byte[]buff=new byte[32];
			int hasRead=0;
			while((hasRead=fis.read(buff))>0)
			{
				fos.write(buff,0,hasRead);
			}
		 }
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

比较高效的读取文件的方法,即采用BufferedInputStream:

public class BufferedInputStreamSample {

	public static void main(String[]args)
	{
		File file=new File("d://error.dat");
		try
		(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));)
		{
		    byte[]buff=new byte[1024];
		    int hasRead=0;
		    while((hasRead=bis.read(buff))>0)
		    {
		    	String content=new String(buff,0,hasRead);
		    	System.out.println(content);
		    }
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}

	}
}

下面是比较高效的写入文件的方法,即采用BufferedOutputStream:

public class BufferedOutputStreamSample {

	public static void main(String[]args)
	{
		String content="I have a dream";
		File file=new File("d://dream.dat");

		byte[]buff=content.getBytes();

		try
		(BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file));)
		{
		    bos.write(buff);
		    //另外,bos还有一个方法是bos.write(byte[],int arg1,int arg2);
		}
	    catch(IOException ex)
	    {
	    	ex.printStackTrace();
	    }

	}
}

下面是FileReader的用法,但是注意FileReader读取文本文件是比较低效的方法:

public class FileReaderSample {

	public static void main(String[]args)
	{
		try(
				FileReader fr=new FileReader("d://error.dat")
			)
		{
			char[]cbuff=new char[32];
			int hasRead=0;
			while((hasRead=fr.read(cbuff))>0)
			{
				System.out.println(new String(cbuff,0,hasRead));
			}

		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

类似地,FileWriter是比较低效的写入文本文件的方法:

public class FileWriterSample {

	public static void main(String[]args)
	{
		try
		(FileWriter fw=new FileWriter("d://poem.txt"))
		{
			fw.write("I have a dream\n");
			fw.write("One day on the red hills of Georgia\n");
			fw.write("The sons of former slaves and the sons of  former slave owner will be able to sit down together at the table.\n");
			fw.write("My four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character.\n");

		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

而BufferedReader是较高效的读取文本文件的方式,但是注意它的构造方法需要一个InputStreamReader,而InpuStreamReader又是包装FileInputStream而来,所以BufferedReader的使用方法如下:

public class BufferedReaderSample {

	public static void main(String[]args)
	{
		try
		(
				//如果是读取文件,则为InputStreamReader reader=new InputStreamReader(new InputStream("d://error.dat"));
				//InputStreamReader reader=new InputStreamReader(new FileInputStream("d://error.dat"));
				InputStreamReader reader=new InputStreamReader(System.in);
				BufferedReader br=new BufferedReader(reader)
		)
		{
		      String buffer=null;
		      while((buffer=br.readLine())!=null)
		      {
		    	  System.out.println(buffer.toUpperCase());
		      }

		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

显然,BufferedReader的好处是具有缓冲功能,它可以一次读取一行文本----以换行符为标志,上例是读取键盘输入后转换为大写并输出,当然,也可以读取文件后将各行转换为大写后输出。

BufferedWriter用法较简单,但是值得注意的是它要flush:

public class BufferedWriterSample {

	public static void main(String[]args)
	{
		try
		(
		     //如果是写入到文件则为OutputStreamWriter writer=new OutputStreamWriter(new FileOutputStream("d://error.dat"));
		     OutputStreamWriter writer=new OutputStreamWriter(System.out);
			 BufferedWriter bw=new BufferedWriter(writer);
		)
		{
			String content="Less is more\nLess is more is not a law\nLess is more is not always correct";
			bw.write(content);
			bw.flush();
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}

	}
}

下面是PrintStream,PrintWriter,BufferedWriter这3个类的对比:

首先是它们的共同点:都是处理流(包装流)而非节点流,因而可以更方便地使用,如PrintStream使用println(String)功能,BufferedWriter使用writer(String)功能;

PrintStream与PrintWriter,BufferedWriter的区别在于前者是处理字节流,而后两者是处理字符流;而BufferedWriter与PrintWriter相比,由于缓冲区的作用,它的效率要比PrintWriter要高。

下面是一个PrintStream的例子:

class Student
{
	int id;
	String name;
	public Student()
	{
		id=0;
		name="Jenny";
	}
	public String toString()
	{
		return "id="+id+" name="+name;
	}
}
public class PrintStreamSample {

	public static void main(String[]args)
	{
		String fileName="d://poem.txt";
		try
		(PrintStream ps=new PrintStream(new FileOutputStream(fileName)))
		{
            //注意:这会把以前的覆盖,要想不覆盖的话,就要使用ps.append的方法而不是println的方法。
			ps.println("Less is more");
			//直接使用println输出对象,这个在Socket编程时很有用。
			ps.println(new Student());
		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

下面是PrintWriter的一个例子:

public class PrintWriterSample {

	public static void main(String[]args)
	{
		try
		(
				PrintWriter writer=new PrintWriter(new OutputStreamWriter(System.out));
		)
		{
			writer.println("Less is more is a important rule.");
			writer.println(true);
		}

	}
}

最后是ObjectInputStream及ObjectOutputStream,利用这两个类来读写序列化对象特别方便,如下所示:

public class ObjectOutputStreamSample {

	public static void main(String[]args)
	{
		Student stu1=new Student(1,"Jack","NewYork");
		Student stu2=new Student(2,"Rose","California");

		File file=new File("d://object.txt");
		//由此可见,BufferedInputStream以及ObjectOutputStream其实都是对FileOutputStream进行了包装。
		try
		(ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file)))
		{
			oos.writeObject(stu1);
			oos.writeObject(stu2);

		}
		catch(IOException ex)
		{
			ex.printStackTrace();
		}

	}
}
class Student implements Serializable{

	private int id;
	private String name;
	private String address;

	public Student(int id,String name,String address)
	{
		this.id=id;
		this.name=name;
		this.address=address;
	}

	@Override
	public String toString()
	{
		StringBuilder sb=new StringBuilder();
		sb.append("id:"+id);
		sb.append("    ");
		sb.append("name:"+name);
		sb.append("    ");
		sb.append("address:"+address);
		return sb.toString();
	}

}
public class ObjectInputStreamSample {

	public static void main(String[]args)
	{
		File file=new File("d://object.txt");
		try
		(ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file)))
		{
			Student stu1=(Student)ois.readObject();
			Student stu2=(Student)ois.readObject();
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}

	}
}
时间: 2024-11-07 03:15:41

深入分析Java中的I/O类的特征及适用场合的相关文章

[转]深入分析 Java 中的中文编码问题

收益匪浅,所以转发至此 原文链接: http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/ 深入分析 Java 中的中文编码问题 编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多.本文将向你详细介绍 Java 中编码问题出现的根本原因,你将了解到:Java 中经常遇到的几种编码格式的区别:Java 中经常需要编码的场景:出现中文问题的原因分析:在开发 Java

深入分析 Java 中的中文编码问题--转

几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言.由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元—— byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解.我们可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须经过一次翻译,把它翻译成英语.这个翻译的过程就是编码.所以可以想

深入分析 Java 中的中文编码问题 (文章来自网络)

许令波,developerWorks 中国网站最佳作者,现就职于淘宝网,是一名 Java 开发工程师.对大型互联网架构设计颇感兴趣,喜欢钻研开源框架的设计原理.有时间将学到的知识整理成文章,也喜欢记录下工作和生活中的一些思考.个人网站是:http://xulingbo.net. 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言.由于人类的语言有太多,因而表示这些语言

深入分析 Java 中的中文编码问题(1)

几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言.由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元—— byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解.我们可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须经过一次翻译,把它翻译成英语.这个翻译的过程就是编码.所以可以想

java中常用的工具类(二)

下面继续分享java中常用的一些工具类,希望给大家带来帮助! 1.FtpUtil Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

Java中的不可变类

本文与个人博客 zhiheng.me 同步发布,标题: Java中的不可变类. 不可变类(Immutable Objects):当类的实例一经创建,其内容便不可改变,即无法修改其成员变量. 可变类(Mutable Objects):类的实例创建后,可以修改其内容. Java 中八个基本类型的包装类和 String 类都属于不可变类,而其他的大多数类都属于可变类. 与引用不可变的区别 需要特别注意的是,不可变类的不可变是指该类的实例不可变而非指向该实例的引用的不可变. String s = "ab

(转载)深入分析 Java 中的中文编码问题

文章源出处   http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/ 几种常见的编码格式 为什么要编码 不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言.由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元—— byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解

java中的日期处理类总结

转自 http://blog.csdn.net/shibenjie/article/details/4263912 java中的日期处理类总结:Date/Calendar/GregorianCalendar/DateFormat/SimpleDateFormat类 今天花了好大一点时间把java的日期类做了一下整理,哈 1.         Date类(该类现在很少用了) l         Date类对象的创建: n         创建一个当前时间 //默认是创建一个代表系统当前日期的Dat

java中常用的工具类(三)

继续分享java中常用的一些工具类.前两篇的文章中有人评论使用Apache 的lang包和IO包,或者Google的Guava库.后续的我会加上的!谢谢支持IT江湖 一.连接数据库的综合类 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53