黑马程序员技术交流社区
标题:
关于流的读取末尾~~~
[打印本页]
作者:
x378320002
时间:
2013-7-3 19:11
标题:
关于流的读取末尾~~~
本帖最后由 x378320002 于 2013-7-4 10:28 编辑
IO流中有read()方法,哪个高手能解释下它是怎么判断这个方法结束的?
文档里只是说在输入数据可用、检测到文件末尾或者抛出异常前,就一直阻塞。
查看源代码是本地代码,看不了,估计看到了也看不懂,不太精通c、c++。
就是输入流怎么知道数据可不可用,是不是流末尾的?
就像毕老师讲课中的模拟浏览器给tomcat发信息的例子
Socket s = new Socket("192.168.1.100",8080);
//模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/1.html HTTP/1.1");
out.println("Accept: */*");
out.println("Host: 192.168.1.100:8080");
out.println("Connection: close");
out.println();
out.println();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
复制代码
并没有给tomcat发送什么结束信息,tomcat那边的读方法为什么不一直阻塞?
还有我自己写的一个上传图片的程序,先上传图片名字,再上传图片的,客户端
// 先发送名字过去---------
OutputStream fout=s.getOutputStream();
fout.write(f.getName().getBytes());
// 在发送内容过去
byte[] barr=new byte[1024];
int len=0;
while((len=fin.read(barr))!=-1){
fout.write(barr, 0, len);
}
复制代码
服务端部分代码
// 从socket读取文件名字
InputStream in = s.getInputStream();
byte[] barr = new byte[1024];
int len = in.read(barr); //--------------这里为什么没有阻塞?
String name = new String(barr, 0, len);
复制代码
我觉得这里的客户端那发送名字和发送内容几乎没有间隔,应该是不行的,我认为服务器端的
int len = in.read(barr);在接收到
名字的数据后会继续阻塞,因为ta但是实际并没有,在接受到名字字符串后就直接建立了文件。
作者:
王磊
时间:
2013-7-3 21:46
本帖最后由 王磊 于 2013-7-3 21:52 编辑
第一个tomcat的例子里,服务器那端没有堵塞是因为已经读到了数据的末尾,这个数据末尾就是客户端发送的请求消息的全部内容都写出完毕,没有数据可写时,就会相当于给服务端写了一个结束的指令,也可以说是服务端没有读到数据,则read方法返回的结果就是-1。这就好像在写一个读取流读一个硬盘文件一样,当read将文件的数据全部读取完毕,最后一次读取的时候没有数据可读,就会收到一个-1的返回值,这样就会判断读取结束。
至于第二个例子,没有阻塞是因为read是一次读取指令,并不是放在循环里,这样客户端发写出的数据一定会被服务端的read方法将缓冲数组写满,一旦写满就意味着这条read执行完毕,楼主说的阻塞情况,一般只有两种情况能发生,一种是read在循环内,一种就是另一边根本就没有写出数据来让read进行读取。
顺便还想看下楼主第二个例子的服务端后续的代码是怎么写的。
作者:
神之梦
时间:
2013-7-3 23:29
我是来拿金币的
作者:
杨兴庭
时间:
2013-7-4 07:38
为了更好的维护论坛的学习氛围,如果您的的问题“已经解决”请即时将帖子状态改成“已解决”
-------------------坚持学习,黑马因你而精彩---------------
作者:
x378320002
时间:
2013-7-4 11:06
本帖最后由 x378320002 于 2013-7-4 11:08 编辑
王磊 发表于 2013-7-3 21:46
第一个tomcat的例子里,服务器那端没有堵塞是因为已经读到了数据的末尾,这个数据末尾就是客户端发送的请求 ...
”这个数据末尾就是客户端发送的请求消息的全部内容都写出完毕,没有数据可写时,就会相当于给服务端写了一个结束的指令“,但是我们并没有显示的发出数据末尾指令啊,是系统自动发的么?如果有的话,客户端这边发末尾指令的标准是什么呢,就像如果客户端发的数据不是连续的,中间隔了几句话,或者Cpu写完第一句去忙别的了,过一会来写第二句,服务端那边不会还等着它回来写末尾指令吧,我推测的是read往数组读取数据但还没有填满数组时可能每次读到空,都会临时阻塞很小一小段时间,以判断真的是没有数据了,如果数组中没有任何数据,则一直阻塞,如果数组中有至少一个数据,则返回数据个数结束本次读取。这个也是猜测,因为我发现我这个例子服务端的那个read(barr)读取的数据并不是每次都一样的,有时候是只有名字那几个字节,并不是每次都会填满,有时候是就会读满。但是在发送名字过去后让线程停止几毫秒,服务端就会非常稳定每次只都读取名字的20字节。
OutputStream fout=s.getOutputStream();
fout.write(f.getName().getBytes());
Thread.sleep(10) //让线程睡觉---------
// 在发送内容过去
byte[] barr=new byte[1024];
你 说的读取一个硬盘文件的好理解,因为那个流在创建时就关联的文件,知道文件的结尾也就是流的结尾在哪里,到时候返回-1就行,而在socket里,里面随时都可能被写入数据,哪怕几句println数据也有可能并不是一次性写入,在没有人为写入结束标记的情况下,它怎么结束的,万一它刚结束对面还有数据要写入呢。
我那个后续代码是这样的
String name = new String(barr, 0, len);
File f = new File("G:\\" + name);
if (!f.exists()) {
f.createNewFile();
}
FileOutputStream fout = new FileOutputStream(f);
while ((len = in.read(barr)) != -1) {
fout.write(barr, 0, len);
}
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
pw.println("上传成功");
fout.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码
作者:
⋛⋌⋚JEEP
时间:
2014-7-15 23:14
:)学习一下
作者:
a191170796
时间:
2014-7-16 10:52
学习一下!!!
作者:
刘斌2014
时间:
2014-8-3 13:17
我是来学习的
作者:
狐狸FMF
时间:
2014-8-13 12:50
好深奥的样子
作者:
狐狸FMF
时间:
2014-8-13 13:03
时过境迁。。。。。。。。。
作者:
凌小歌
时间:
2014-9-15 09:53
学习一下。。。
作者:
黄小橙
时间:
2014-10-4 09:20
学习了!
作者:
杨佳名
时间:
2014-10-6 13:52
学习一下。。。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2