java基础:字节流和字符流的转换


我们的机器只会读字节码,而我们人却很难读懂字节码,所以人与机器交流过程中需要编码解码。

InputStreamReader及其子类FileReader:(从字节到字符)是个解码过程;

OutputStreamWrite及其子类FileWriter:(从字符到字节)是个编码过程。

InputStreamReader这个解码过程中,最主要的就是StreamDecoder



  1. InputStreamReader的过程要指定编码字符集,否则将采用操作系统默认字符集,很可能会出现乱码问题。(查看JDK中的InputStreamReader类的构造函数,除了第一个构造函数没有制定外,其他几个都需要指定)

  2. 如果看不懂这个图请先看Association,Aggregation and Composition这篇文章。

  3. 现在对于这张图我们还有个难点没有解决:StreamDecoder是个什么东西?这个,这个工作就有点复杂了,网上资料比较少,我自己找源码看看:

public class InputStreamReader extends Reader {
    private final StreamDecoder sd;//由上图已知在InputStreamReader中一定有一个StreamDecoder对象
	public InputStreamReader(InputStream in) {//InputStreamReader有多个构造方法,我假设它用的就是这个
        super(in);
        try {
			  // 创建一个StreamDecoder对象
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // 用系统默认编码
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw new Error(e);
        }
    }
	public int read() throws IOException {
		// 看猫腻来了,竟然实际上是StreamDecoder在read
        return sd.read();
    }
/**其他的方法我们不管,看有关的就行**/
}
好,再来看看JDK7中的StreamDecoder(eclipse中显示不出,我也不知道为什么,我在这个网址看的源码点一下)是怎么实现的:
public class StreamDecoder extends Reader{
	private static final int MIN_BYTE_BUFFER_SIZE = 32;
	private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
	private Charset cs;
	private CharsetDecoder decoder;
	private ByteBuffer bb;

	// 由上述的 forInputStreamReader方法的参数可知用的是下面这个方法
	public static StreamDecoder forInputStreamReader(InputStream in,Object lock,String charsetName) throws UnsupportedEncodingException {
		String csn = charsetName;
       if (csn == null)	// 由于用的是默认编码,会执行这句
       csn = Charset.defaultCharset().name();
       try {
       	if (Charset.isSupported(csn))	// 检测JVM是否支持该编码集
				
              return new StreamDecoder(in, lock, Charset.forName(csn));
       } catch (IllegalCharsetNameException x) { }
              throw new UnsupportedEncodingException (csn);
	}
	
	StreamDecoder(InputStream in, Object lock, Charset cs) {
        this(in, lock, cs.newDecoder().onMalformedInput(CodingErrorAction
						.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
		// 额,说明它是在用Charset对象产生CharsetDecoder对象,目的是为了执行另一个构造函数
    }

	StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
		//  CharsetDecoder:是一个引擎,可以将一个字节序列按照特定的字符集转换成一个16位的Unicode序列
             super(lock);
             this.cs = dec.charset();
             this.decoder = dec;
     	// 下面的代码先不用管,我们这里用不上
             // This path disabled until direct buffers are faster
             if (false && in instanceof FileInputStream) {
             		ch = getChannel((FileInputStream)in);
             		if (ch != null)
                 		bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
             	}
             	if (ch == null) {
             		this.in = in;
             		this.ch = null;
             		bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
             	}
             	bb.flip();                      // So that bb is initially empty
	}
	// 调用的就是这个函数吧
	public int read() throws IOException {
		return read0(); //额,又是假的;继续看
	}
	private int read0() throws IOException {
		synchronized (lock) {
			// Return the leftover char, if there is one
			if (haveLeftoverChar) {
				haveLeftoverChar = false;
				return leftoverChar;
			}
			// Convert more bytessz
			char cb[] = new char[2];	//一次读两个字节
			int n = read(cb, 0, 2);
			switch (n) {
				case -1:
					return -1;
				case 2:
					leftoverChar = cb[1];
  					haveLeftoverChar = true;
				// FALL THROUGH
				case 1:
					return cb[0];
				default:
					assert false : n;
					return -1;
			}// end of catch
		}// end of  synchronized
	}

}

明白了是谁真正负责转换了吧,哈哈

OutputStreamWrite编码过程中就有另外一个重要的类:StreamEncoder负责编码
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值