NIO FileChannelImpl解析

在调用fileChannle.write(ByteBuffer[] src)底层是怎么实现的?是循环写?Direct和No-Direct有什么区变?

下面结合源码来说明:

 

 

 

static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) throws IOException {
		int nextWithRemaining = remaining(bufs);
		// if all bufs are empty we should return immediately
		if (nextWithRemaining < 0)
			return 0;
		// If some bufs are empty we should skip them
		if (nextWithRemaining > 0)
			bufs = skipBufs(bufs, nextWithRemaining);

		int numBufs = bufs.length;
		int bytesReadyToWrite = 0;

		// Create shadow to ensure DirectByteBuffers are used
		// 这里可以看出使用DirectBuffer要节省一次copy动作,对大数据量来说是相当可观的
		ByteBuffer[] shadow = new ByteBuffer[numBufs];
		for (int i = 0; i < numBufs; i++) {
			if (!(bufs[i] instanceof DirectBuffer)) {
				int pos = bufs[i].position();
				int lim = bufs[i].limit();
				assert (pos <= lim);
				int rem = (pos <= lim ? lim - pos : 0);

				ByteBuffer bb = ByteBuffer.allocateDirect(rem);
				shadow[i] = bb;
				// Leave slow buffer position untouched; it will be updated
				// after we see how many bytes were really written out
				bb.put(bufs[i]);
				bufs[i].position(pos);
				bb.flip();
			} else {
				shadow[i] = bufs[i];
			}
		}

		IOVecWrapper vec = null;
		long bytesWritten = 0;
		try {
			// Create a native iovec array
			vec = new IOVecWrapper(numBufs);

			// Fill in the iovec array with appropriate data
			//这里将DirectBuffer数据转化成IOVec的结构体,此结构体是系统调用writev的参数
			for (int i = 0; i < numBufs; i++) {
				ByteBuffer nextBuffer = shadow[i];
				// put in the buffer addresses
				long pos = nextBuffer.position();
				long len = nextBuffer.limit() - pos;
				bytesReadyToWrite += len;
				vec.putBase(i, ((DirectBuffer) nextBuffer).address() + pos);
				vec.putLen(i, len);
			}

			// Invoke native call to fill the buffers
			// jni系统调用writev, 此函数作用是聚集写,所以在这里没有应用层的循环写
			bytesWritten = nd.writev(fd, vec.address, numBufs);
		} finally {
			vec.free();
		}
		long returnVal = bytesWritten;

		// Notify the buffers how many bytes were taken
		// 按照写入的字节数,更新原始的ByteBuffers
		for (int i = 0; i < numBufs; i++) {
			ByteBuffer nextBuffer = bufs[i];
			int pos = nextBuffer.position();
			int lim = nextBuffer.limit();
			assert (pos <= lim);
			int len = (pos <= lim ? lim - pos : lim);
			if (bytesWritten >= len) {
				bytesWritten -= len;
				int newPosition = pos + len;
				nextBuffer.position(newPosition);
			} else { // Buffers not completely filled
				if (bytesWritten > 0) {
					assert (pos + bytesWritten < (long) Integer.MAX_VALUE);
					int newPosition = (int) (pos + bytesWritten);
					nextBuffer.position(newPosition);
				}
				break;
			}
		}
		return returnVal;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值