【java中的IO知识小结】

NIO以通道channel和缓冲区Buffer为基础来实现面向块的IO数据处理,

Channel,Buffer 和 Selector 构成了NIO核心的API。

流分类

输入流/输出流 -->InputStream / Reader     OutputStream / Writer

字节流/字符流

字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream

在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,

在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。

字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好。所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。字节流是最基本的,所有的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的 

1.Java的字节流  InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先。 

2.Java的字符流   Reader是所有读取字符串输入流的祖先,而writer是所有输出字符串的祖先。 

3.字符流使用了缓冲区,而字节流没有使用缓冲区

4、字节流主要是操作byte类型数据,以byte数组为准,字符流处理的单元为2个字节的Unicode字符

InputStream,OutputStream,Reader,writer都是抽象类。所以不能直接new 

字节流是最基本的,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的。在从字节流转化为字符流时,实际上就是byte[]转化为String时, public String(byte bytes[], String charsetName) 有一个关键的参数字符集编码,通常我们都省略了,那系统就用操作系统的lang 而在字符流转化为字节流时,实际上是String转化为byte[]时, byte[] String.getBytes(String charsetName) 也是一样的道理

字节流与字符流的区别

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

那开发中究竟用字节流好还是用字符流好呢?

在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

如果要java程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。

使用字节流不关闭执行

package cn.com.demo.nio;

import java.io.File;

import java.io.FileOutputStream;

import java.io.OutputStream;

public class OutputStreamDemo05 {

public static void main(String[] args) throws Exception { // 异常抛出, 不处理

// 第1步:使用File类找到一个文件

File f = new File("d:" + File.separator + "test.txt"); // 声明File 对象

// 第2步:通过子类实例化父类对象

OutputStream out = null;

// 准备好一个输出的对象

out = new FileOutputStream(f);

// 通过对象多态性进行实例化

// 第3步:进行写操作

String str = "Hello World!!!";

// 准备一个字符串

byte b[] = str.getBytes();

// 字符串转byte数组

out.write(b);

// 将内容输出

// 第4步:关闭输出流

// out.close();

// 此时没有关闭

}

}

程序运行结果:  此时没有关闭字节流操作,但是文件中也依然存在了输出的内容,证明字节流是直接操作文件本身的而下面继续使用字符流完成,再观察效果。

范例:使用字符流不关闭执行

import java.io.File;

import java.io.FileWriter;

import java.io.Writer;

public class WriterDemo03 {

public static void main(String[] args) throws Exception { // 异常抛出, 不处理

// 第1步:使用File类找到一个文件

File f = new File("d:" + File.separator + "test.txt");// 声明File 对象

// 第2步:通过子类实例化父类对象

Writer out = null;

// 准备好一个输出的对象

out = new FileWriter(f);

// 通过对象多态性进行实例化

// 第3步:进行写操作

String str = "Hello World!!!";

// 准备一个字符串

out.write(str);

// 将内容输出

// 第4步:关闭输出流

// out.close();

// 此时没有关闭

}

}

程序运行后会发现文件中没有任何内容,这是因为字符流操作时使用了缓冲区,而   在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的,所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区

强制性清空缓冲区

package cn.com.demo.nio;

import java.io.File;

import java.io.FileWriter;

import java.io.Writer;

public class WriterDemo04 {

public static void main(String[] args) throws Exception { // 异常抛出不处理

// 第1步:使用File类找到一个文件

File f = new File("d:" + File.separator + "test.txt");// 声明File 对象

// 第2步:通过子类实例化父类对象

Writer out = null;

// 准备好一个输出的对象

out = new FileWriter(f);

// 通过对象多态性进行实例化

// 第3步:进行写操作

String str = "Hello World!!!";

// 准备一个字符串

out.write(str);

// 将内容输出

out.flush();

// 强制性清空缓冲区中的内容

// 第4步:关闭输出流

// out.close();

// 此时没有关闭

}

}

程序运行结果:  此时,文件中已经存在了内容,更进一步证明内容是保存在缓冲区的。

JDK文档参考

Reader用于读取字符流的抽象类。 

public abstract class Reader extends Object implements Readable, Closeable

Writer 写入字符流的抽象类。    

public abstract class Writer extends Object implements Appendable, Closeable, Flushable

public class OutputStreamWriter extends Writer

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。 

每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。 

为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如: 

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

public class InputStreamReader extends Reader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。 

每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。 

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如: 

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

InputStream抽象类是表示字节输入流的所有类的超类。

public abstract class InputStream extends Object implements Closeable

此抽象类是表示输出字节流的所有类的超类。

输出流接受输出字节并将这些字节发送到某个接收器。

public abstract class OutputStream  extends Object  implements Closeable, Flushable

猜你喜欢

转载自gaojingsong.iteye.com/blog/2333756