javaIO字节流与字符流

流分类

在java.io 包中,操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。

  • 字节流:InputStream(字节输入流)、OutputStream(字节输出流); 
  • 字符流:Reader(字符输入流)、Writer(字符输出流);

字节流理解配图

字符流理解配图

字节流与字符流的区别

字节与字符的区别   

     如果要明白字节流与字符流的区别,首先需要明白字节和字符的区别

  • 字节byte

       它是计算机的数据存储单元,每个字节包括8个二进制位-bit”,可以保存8位的二进制数

       由于受到电子设备的物理特定限制,例如磁性存储器只适合保存两种状态的信息—磁性的强弱、以电信号的方式也只适合传递两种状态的信息—电压的高低。

     因此在计算机中最终结果时再将转换为人们熟悉的格式,如十进制数值、字符和图形等。

  • 字符集Charset

        为了实现对字符信息的存储,人们将可能用到的字符排成一个有序的字符队列,这种由多个有序字符组成的集合称为“字符集-Charset”,而在计算机中实际保存的是字符在字符集中的序号,即一个二进制形式的整数。而到底采用1个还是多个字节以及具体如何来存储一个字符集的字符,这种相关的规定被称为“编码-Encoding”。

       常见的字符集有ISO-8859-1(一个字符占一个字节)、GB2312(一个字符占两个字节)、GBK(一个字符占两个字节)、UTF-8(变长编码,根据不同的Unicode字符,用1到6个字节编码)

  • 字符char

        (1) 用英文单引号括起来的单个字符,例如:'a'、'字'。这是最常见的声明字符形式。

        (2) 用英文单引号括起来的十六进制字符代码值来表示单个字符。其格式为:'uXXXX',其中u是约定的前缀(u是unicode的第一个字母),而后面的XXXX位4位十六进制数,是该字符在unicode字符集中的序号。例如:'uFFFF'。    

         通过上面的字符与字节的区别,我们就可以知道,任何终端(网络、文件)读取或者输出的数据都一定是字节,字符是经过内存处理后的数据。

  • 字符输入:字节(磁盘)–> 自动转换为 –>字符(内存);
  • 字符输出:字符(内存)–> 自动转换为–>字节(磁盘);

字节流与字符流区别

  • 字节流

        字节流的处理单元为1个字节,操作字节和字节数组。字节流更加适用于音频文件、图片、歌曲,操作中文文本可能会出现乱码。字节流在操作过程中不会使用到缓冲区,直接对文件本身进行操作。

  • 字符流

       字节流读取文字字节数据后,不直接操作而是先查指定的编码表。获取对应的文字。在对这个文字进行操作。即:字节流+编码表,在操作的过程中不能只读取一个字节,否则不能将字节根据字符集转换成相应的字符,因此需要缓存区。 字符流在操作的时候是需要使用到缓冲区的,因此需要使用close方法才能输出内容,或调用flush方法强制刷新缓冲区。

流的操作

        不管使用的是字节流还是字符流,其基本的操作流程几乎是一样的,以文件操作为例。

  1. 创建File类对象 ,主要是指明要操作的文件路径;
  2. 根据字节流或字符流的子类实例化父类对象 ;
  3. 进行数据的读取或写入操作;
  4. 关闭流(close());

对于IO操作属于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)最后必须要进行关闭。

字节输入流InputStream

public abstract class InputStream implements Closeable 

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

Modifier and Type Method and Description
void close()

关闭此输入流并释放与流相关联的任何系统资源。

abstract int

read() 从输入流读取数据的下一个字节。

该方法阻塞直到输入数据可用,检测到流的结尾,或抛出异常。

该方法是一个抽象方法,需要子类去根据自己的数据类型去实现,后面的read(byte[] b)、read(byte[] b,int off,int len)底层都是调用的该方法

int

读取到缓冲区的总字节数,

或者如果没有更多的数据,因为已经到达流的末尾,则是 -1 

read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区 b 。

该方法阻塞直到输入数据可用,检测到文件结束或抛出异常。

如果b的长度为零,则不会读取字节并返回0 ; 否则,尝试读取至少一个字节。

如果没有字节可用,因为流在文件末尾,则返回值-1 ; 否则,读取至少一个字节并存储到b 。

读取的字节数最多等于b的长度,令k为实际要读取的字节数;

如果k < b的长度,这些字节将存储在元素b[0]b[ k -1],使元素b[ k ]b[b.length-1]不受影响。

如果k>= b的长度,那么最多读取d的长度的字节。

int

读取到缓冲区的总字节数,如果没有更多的数据,因为已经到达流的末尾,那么 -1 

read(byte[] b, int off, int len)

b - 读取数据的缓冲区。

off - 写入数据的数组 b中的起始偏移量。

len - 要读取的最大字节数。

从输入流读取最多 len字节的数据到一个字节数组。

该方法阻塞直到输入数据可用,检测到流的结尾,或抛出异常。

如果len为零,则不会读取字节并返回0 ; 否则,尝试读取至少一个字节。 

如果没有字节可用,因为流是文件的-1则返回值-1 ; 否则,读取至少一个字节并存储到b 。

第一个字节读取存储在元素b[off] ,下一个字节存入b[off+1] ,等等。

读取的字节数最多等于len , 令k为实际读取的字节数; 

这些字节将存储在元素b[off]b[off+ k -1] ,使元素b[off+ k ]b[off+len-1]不受影响。

在每种情况下,元件b[0]b[off]和元件b[off+len]b[b.length-1]不受影响。

字节输出流OutputStream

public abstract class OutputStream implements Closeable, Flushable

这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。

Modifier and Type Method and Description
void close()

关闭此输出流并释放与此流相关联的任何系统资源。

void flush()

刷新此输出流并强制任何缓冲的输出字节被写出。

void write(byte[] b)

将 b.length字节从指定的字节数组写入此输出流。

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

从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。

write(b, off, len)的一般合同是数组b中的一些字节按顺序写入输出流; 

元素b[off]是写入的第一个字节, b[off+len-1]是此操作写入的最后一个字节。

abstract void write(int b)

将指定的字节写入此输出流。 write的一般合同是将一个字节写入输出流。 

要写入的字节是参数b的八个低位。 b的24个高位被忽略。

因为InputStream和OutputStream都是抽象类,在使用中用到的是他们的子类。

我们ByteArrayOutputStream和ByteArrayInputStream子类写了测试的例子

public class TestIO {

	public static void main(String[] args) throws IOException {
		byte[] bytes = "hello world".getBytes();
		// 实例化输出流对象
		OutputStream outputStream = new ByteArrayOutputStream(5);
		// 写操作
		outputStream.write(bytes);
		// 关闭流
		outputStream.close();

		// 作为InputStream使用的缓冲区数组
		byte[] inByteArray = new byte[20];
		InputStream intputStream = new ByteArrayInputStream(bytes);
		// 读取字节数据,将其放入到缓存区数组中,返回读取的长度
		int len = intputStream.read(inByteArray);

		System.out.println("length:" + len);
		System.out.println("content:" + new String(inByteArray, 0, len));
		// 关闭流
		intputStream.close();
	}

}

打印结果如下(可以通过调整缓存区字节数组的长度来测试读写的长度验证)

length:11
content:hello world

字符输入流Reader

public abstract class Reader implements Readable, Closeable

用于读取字符流的抽象类。 子类必须实现的唯一方法是read(char [],int,int)和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,附加的功能或两者。

Modifier and Type Method and Description
abstract void close()

关闭流并释放与之相关联的任何系统资源。

int read()

读一个字符

该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。

int read(char[] cbuf)

将字符读入数组。

该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。

abstract int read(char[] cbuf, int off, int len)

将字符读入数组的一部分。

该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。

int read(CharBuffer target)

尝试将字符读入指定的字符缓冲区。

字符输出流Writer

public abstract class Writer implements Appendable, Closeable, Flushable

        子类必须实现的唯一方法是write(char [],int,int),flush()和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,附加的功能或两者。

Writer append(char c)

将指定的字符附加到此作者。

Writer append(CharSequence csq)

将指定的字符序列附加到此作者。

Writer append(CharSequence csq, int start, int end)

将指定字符序列的子序列附加到此作者。

abstract void close()

关闭流,先刷新。

abstract void flush()

刷新流。

void write(char[] cbuf)

写入一个字符数组。

abstract void write(char[] cbuf, int off, int len)

写入字符数组的一部分。

void write(int c)

写一个字符

void write(String str)

写一个字符串

void write(String str, int off, int len)

写一个字符串的一部分。

使用StringWriter和StringReader写的测试的例子 

	public static void main(String[] args) throws IOException {
		String str = "hello world";
		// 实例化输出流对象
		StringWriter write = new StringWriter();
		// 写操作
		write.write(str);
		// 刷新流
		write.flush();
		// 关闭流
		write.close();

		// 创建一个新的字符串阅读器
		StringReader intputReader = new StringReader(str);
		char[] c = new char[1024];
		int temp = 0;
		int len = 0;// 接收每一个读取进来的数据
		while ((temp = intputReader.read()) != -1) {
			// 如果文件还有内容
			c[len] = (char) temp;
			len++;
		}
		// 关闭流
		intputReader.close();

		System.out.println("length:" + len);
		System.out.println("content:" + new String(c, 0, len));
	}

字节流到字符流的桥InputStreamReader

Reader的一个子类

public class InputStreamReader extends Reader

        InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

        每个调用InputStreamReader的read()方法之一可能会导致从底层字节输入流读取一个或多个字节。 为了使字节有效地转换为字符,可以从底层流读取比满足当前读取操作所需的更多字节。

        为了最大的效率,请考虑在BufferedReader中包装一个InputStreamReader。 例如:

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

 构造方法如下

Constructor and Description
InputStreamReader(InputStream in)

创建一个使用默认字符集的InputStreamReader。

InputStreamReader(InputStream in, Charset cs)

创建一个使用给定字符集的InputStreamReader。

InputStreamReader(InputStream in, CharsetDecoder dec)

创建一个使用给定字符集解码器的InputStreamReader。

InputStreamReader(InputStream in, String charsetName)

创建一个使用命名字符集的InputStreamReader。

字符流到字节流的桥OutputStreamWriter

public class OutputStreamWriter extends Writer

        OutputStreamWriter是字符流到字节流的桥梁:通过指定的字符集charset把向其写入的字符编码成字节 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

        每次调用write()方法都会使编码转换器在给定字符上被调用。 所得到的字节在写入底层输出流之前累积在缓冲区中。 可以指定此缓冲区的大小,但是默认情况下它大部分用于大多数目的。 请注意,传递给write()方法的字符不会缓冲。

        为了最大的效率,请考虑在BufferedWriter中包装一个OutputStreamWriter,以避免频繁的转换器调用。 例如:

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

构造方法如下

Constructor and Description
OutputStreamWriter(OutputStream out)

创建一个使用默认字符编码的OutputStreamWriter。

OutputStreamWriter(OutputStream out, Charset cs)

创建一个使用给定字符集的OutputStreamWriter。

OutputStreamWriter(OutputStream out, CharsetEncoder enc)

创建一个使用给定字符集编码器的OutputStreamWriter。

OutputStreamWriter(OutputStream out, String charsetName)

创建一个使用命名字符集的OutputStreamWriter。

字节流、字符流图

发布了212 篇原创文章 · 获赞 135 · 访问量 137万+

猜你喜欢

转载自blog.csdn.net/ystyaoshengting/article/details/103842406