面向流,面向缓冲区,这是JAVA中的概念,和操作系统无关
具体怎么看呢,废话少说直接上源码
第一段是JAVA中的标准IO
java.net.SocketInputStream.read
int read(byte b[], int off, int length, int timeout) throws IOException { int n; // EOF already encountered if (eof) { return -1; } // connection reset if (impl.isConnectionReset()) { throw new SocketException("Connection reset"); } // bounds check if (length <= 0 || off < 0 || off + length > b.length) { if (length == 0) { return 0; } throw new ArrayIndexOutOfBoundsException(); } boolean gotReset = false; // acquire file descriptor and do the read FileDescriptor fd = impl.acquireFD(); try { n = socketRead(fd, b, off, length, timeout);//native函数 if (n > 0) { return n; } } catch (ConnectionResetException rstExc) { gotReset = true; } finally { impl.releaseFD(); } /* * We receive a "connection reset" but there may be bytes still * buffered on the socket */ if (gotReset) { impl.setConnectionResetPending(); impl.acquireFD(); try { n = socketRead(fd, b, off, length, timeout);//native函数,这里从内核态中读取数据到数组b中 if (n > 0) { return n; } } catch (ConnectionResetException rstExc) { } finally { impl.releaseFD(); } } /* * If we get here we are at EOF, the socket has been closed, * or the connection has been reset. */ if (impl.isClosedOrPending()) { throw new SocketException("Socket closed"); } if (impl.isConnectionResetPending()) { impl.setConnectionReset(); } if (impl.isConnectionReset()) { throw new SocketException("Connection reset"); } eof = true; return -1; }第二段代码是一般说的NIO实现方式
sun.nio.ch.DatagramChannelImpl.receive
private int receive(FileDescriptor fd, ByteBuffer dst) throws IOException { int pos = dst.position(); int lim = dst.limit(); assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); if (dst instanceof DirectBuffer && rem > 0) return receiveIntoNativeBuffer(fd, dst, rem, pos); // Substitute a native buffer. If the supplied buffer is empty // we must instead use a nonempty buffer, otherwise the call // will not block waiting for a datagram on some platforms. int newSize = Math.max(rem, 1); ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);//申请一块newSize大小的缓冲区块 try { int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);//数据读取到缓冲区中,buffer可以做标记,操作指针等 bb.flip(); if (n > 0 && rem > 0) dst.put(bb); return n; } finally { Util.releaseTemporaryDirectBuffer(bb); } }可以看到,第一段代码中一次性从native函数中获取相当长度的数据,然后直接对这块数据进行了操作 而第二段代码中Util.getTemporaryDirectBuffer(newSize);申请了一块堆外内存,每次读取的数据放在该内存中,然后对该内存进行操作。 一般说法面向缓存相对于面向流的好处在于增加了处理数据的灵活性,当然也增加了操作的复杂度,比如当更多数据取入时,是否会覆盖前面的数据等