日记 - 关于inputStream的read以及byte

最近在整socket,然后在读取这里出了点事,好在解决了,现在记录一下,下面开始贴代码,关于inputstream以及它的read方法搞出的问题。

 

InputStream

1,这是一个测试且失败了的例子

        String src = "今天的天气真的不好";

        byte[] buff = new byte[1024];

        InputStream is = new ByteArrayInputStream(src.getBytes("utf-8"));

        int len = -1;

        StringBuffer sb = new StringBuffer();

        while(-1 != (len = is.read())) {

            sb.append((char)len);

            System.out.println(sb);

        }

    sb全是乱码,没有得到我想要的。但是如果将src换成“Hello!”却能在控制台完整输出

 

2,这是测试正确可用的

        String src = "今天的天气真的不好";

        byte[] buff = new byte[1024];

        InputStream is = new ByteArrayInputStream(src.getBytes("utf-8"));

        int len = -1;

        while(-1 != (len = is.read(buff))) {

            String str1 = new String(buff, 0, len);//new String(buff, 0, len, "UTF-8")这是两个方法的合体

            String str2 = new String(buff, "UTF-8");

            System.out.println(str1);

            System.out.println(str2);

        }

    因为编码问题而开始寻求解决方案的我,在这里找到了答案,str1和str2在代码中的控制台输出结果有些不太一样。同时请注意is.read方法的参数,在代码1中是无参数的,代码二中是有参数的。

    根据代码来看,is.read()方法的返回值就是一个byte的ASCLL码dec数(dec是十进制)。而is.read(buff)的返回值是byte的字节数(也就是有几个byte,代码2中是27),而buff数组中则插入了is读取的27个byte。

    而控制台输出结果str1是完美答案,而str2则是“今天的天气真的不好\u0000\u0000... ...”,至于为什么,看看代码就知道了。

 

3,

      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

      String str = in.readLine();

    这个也是可用的,但是这里我测试的时候出了一个问题。我写的服务端和客户端可以正确交互,但是跟C#写的客户端交互就出现问题,后来证实是编码问题。in.readLine()方法是读取一行数据,遇到换行符号时就停止,直到下次再来读取。

 

 然而上述部分的代码并没啥卵用。

 我在这里讨论inputStream是基于我在使用socket。然后上面的写法在socket是然并卵的。因为read()几乎不会返回-1,当你读取完in里的byte后,read()会直接进入阻塞,不会返回-1,而且作为服务器,接入一个链接后,还要考虑线程问题,在代码的设计上最好就是使用while(true)的方式反复轮询,然后在轮询内进行read(),或者给轮询其他的判断条件。由于socket发送的是流,不像http一样有信息头,还存在粘包的问题。所以我采用的办法是先读取前两个字节,根据这两个字节所转化的数字来读取后续的字节数,由此开始byte的话题。

 

Byte

  两个byte可以转化成一个short,四个byte可转成一个int。而一个short的范围215-1到-215。

  所以我先读取前两个byte,转成short,假设值为45,那么就接着再读45取个字节,再转成所需信息,然后进入下一次的循环。然后这里我就有一个疑问了,因为我是培训出身,没什么基础知识,不明白为什么两个byte能转成short能代表正三万至负三万的数字,我开始钻牛角尖。

  0000 0000,这里是8个位(bit),等于一个byte,每个位都是一个二进制(每一位只能有0或者1,如果是十进制就是0-9)而。那么这8个位的二进制能代表多少数字呢?

  答案是2的8次幂减一,等于255(一个0能存2个数,00能存4个数,分别是00、01、10、11,以此类推)。这里有一个小问题,为什么要减一?1至9是九个数字,0至9是十个数字,而一个byte代表的是0至255。

  如果要存一个256该怎么办,一个byte存不下,一个255是八位的1111 1111,如果再加1,就会变成1 0000 0000,但是这就变成9位了,所以一个byte存不下,需要两个byte,所以是00000001  00000000。

  以上就是为什么两个byte能等于一个这么大的数的原因。

  

  然后我看了一个关于字节序的东西,开始弄不明白,主要是里面关于的“高”和“低”。

  字节序分两类Big-Endian和Little-Endian。下面来贴个图:



  上面这图什么意思呢?

  byte[]数组,你存的时候,假设你存一个String的“HELLO”

  byte[] buf = new byte[5];

  那么这个时候buf[0] = 72,buf[1] = 69,buf[2] = 76,buf[3] = 76,buf[4] = 79。这里不是赋值,这里的数字是“HELLO”分别转化成十进制的ascll码,72是H。按照上图的解释就是说72是储存在栈顶的低地址中(buf[0]就处于栈顶)。72属于低字节,79属于高字节,这就是一个车头和车尾的区别。

  那么接下来贴第二张图,这是以0x12345678为例子:

 

  其实这两种字节序,就好比是一辆车,进车库的时候是车头先进车库还是车尾先进车库。一般PC是低字节序,如果按平时书写习惯,从左到右是高位到低位的顺序,就是Little-Endian。

  好了,文章的主要内容就这些。

 

 

同时推荐大家去看看NIO,所谓的新IO

NIO与传统IO的区别:http://blog.csdn.net/zhouhl_cn/article/details/6568119

Java NIO原理 图文分析及代码实现:http://weixiaolu.iteye.com/blog/1479656

 

猜你喜欢

转载自lcl088005.iteye.com/blog/2242712