字节流判断读到流末尾的标记是什么以及他的返回值为什么是0-255

我查询了InputStream的api,关于read()方法的说明是:返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。我的问题:一个字节可以表示的范围是-128 --- +127为什么api上说读到的范围是0-255,还有就是read是根据什么判断到了流的末尾的,他的结束标记是什么。
现在我已经知道为什么是反255了,原因是返回int符号位转变的原因,现在就问怎么判断刘末尾的,以及
System.out.println("a"+"\r"+"b");
System.out.println("a"+"\n"+"b");
System.out.println("a"+"\r\n"+"b");//效果为什么一样?

判断末尾的问题,首先InputStream这个类是一个抽象类,其中read()方法也是抽象方法,其具体实现,根据其子类不同而不同。以其两个子类为例,ByteArrayInputStream是通过判断当前的位置是否已经达到数组长度来判断是否结尾,FileInputStream则是通过判断是否读到文件尾来判断结尾。

补充说明一下关于255的问题。read()方法的返回值虽然是int,但这么理解是不好的,read()方法的返回值是InputStream的下一个字节,只是放在int的最后一个字节里。通常这个字节的int值,只要不是-1,没人会关心的。255的原因不是什么符号位的问题,只是一个int如果只有最后一个字节有效而其他都是0的话,范围就是0-255。

"\r"和"\n"的区别实际上是不同操作系统使用不同换行符的问题。
windows使用 \n\r 或 \r\n 来作为换行符。\r是回到当前行的头部,\n是移动到下一行
Mac OS使用 \r 来作为换行符
类Unix使用 \n 来作为换行符

至于你看到输出效果一样,是IDE的问题,IDE要跨平台,会把\r,\n\,\r\n都解释为换行。

一下说明均以windows平台为例
以如下程序段为例:

System.out.println("gggggg"+"\r"+"eeeee");
System.out.println("dddd"+"\n"+"ccc");
System.out.println("aa"+"\r\n"+"b");

直接在IDE(我用eclipse)中执行,显示为:
gggggg
eeeee
dddd
ccc
aa
b

在命令行中执行java test,显示为:
eeeeeg
dddd
ccc
aa
b

如果再命令行中执行java test > test.txt,也就是把输出重定向到test.txt文件里,然后用记事本打开,你会看到:
ggggggeeeee
ddddccc
aab

记事本不会把\n和\r单独解释,所以ddddccc显示在一行了。但是这些字符确实藏在哪一行里。
不信你可以全选,Ctrl+C,然后拷贝到百度知道这里某个文本框里,你会看到和IDE一样的输出。这事因为IDE和网页要跨平台,会把\r,\n\,\r\n都解释为换行。追问

ByteArrayInputStream听着名字就是个包装类,其实这些包装类底层都是用的字节流,只不过里面搞个个数组做为缓冲以加强io的性能,那么底层流往数组里按照角标来填充数据,问题的关键在于从源里读的过程是怎么判断读完的,你的回答是在说包装类是怎么添满缓充的,和我的问题没对上,关于换行符的确实如你所说没错。

追答

不,InputStream并不仅仅是为IO设计的,InputStream仅仅是字节流而已。ByteArrayInputStream这个类是InputStream的子类,其目的是将byte[]当做字节流来处理,和IO没有关系,这个类里面,实际上就是一个数组,只不过以字节流的形式访问。

我不太清楚你所指的包装类是什么,你可能用错了名词。我所知道的包装类指的是将int,long等包装成Integer,Long这样的包装类。

追问

我说的是字节流的所有子类,sun在设计的时候就是通过包装设计模式设计的,包装设计模式就是把个祖宗类包装起来加强他的功能。

追答

哦,你说的是这个包装。

首先你应该意识到,InputStream这个类是一个抽象类,其中read()方法是这样的:

public abstract int read() throws IOException;
这个方法的具体实现,都不仅仅是加强了,而是完全依赖于其子类的实现方法。
事实上,InputStream本身几乎没有提供任何有意义的方法实现。

你可以看到ByteArrayInputStream 的代码是这样的:
public class ByteArrayInputStream extends InputStream {
....

protected byte buf[];
protected int pos;

public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}

public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
....
}
这里事实上就和IO完全没有任何关系了。

而FileInputStream的read则是:
public native int read() throws IOException;
这样调用了JNI。这里的结尾判断,则是通过判断是否到达了文件尾来确定的。

另外关于“底层都是用的字节流”这句,你其实弄反了,底层都是别的东西,字节流才是表象。ByteArrayInputStream 的底层是一个byte[],FileInputStream的底层是一个FileChannel。

再有就是这里不是包装模式,请不要混淆。

追问

太感谢了,我明白了,谢谢。

温馨提示:内容为网友见解,仅供参考
无其他回答
相似回答