java file transferto_jvm源码分析之FileChannel.transferTo()方法

FileChannel.transferTo()方法

public abstract long transferTo(long position, long count,

WritableByteChannel target)

throws IOException;

FileChannelImpl.transferTo()方法

public long transferTo(long position, long count,

WritableByteChannel target)

throws IOException

{

ensureOpen();

if (!target.isOpen())

throw new ClosedChannelException();

if (!readable)

throw new NonReadableChannelException();

if (target instanceof FileChannelImpl &&

!((FileChannelImpl)target).writable)

throw new NonWritableChannelException();

if ((position < 0) || (count < 0))

throw new IllegalArgumentException();

long sz = size();

if (position > sz)

return 0;

int icount = (int)Math.min(count, Integer.MAX_VALUE);

if ((sz - position) < icount)

icount = (int)(sz - position);

long n;

// Attempt a direct transfer, if the kernel supports it

if ((n = transferToDirectly(position, icount, target)) >= 0)

return n;

// Attempt a mapped transfer, but only to trusted channel types

if ((n = transferToTrustedChannel(position, icount, target)) >= 0)

return n;

// Slow path for untrusted targets

return transferToArbitraryChannel(position, icount, target);

}

transferToDirectly()方法

private long transferToDirectly(long position, int icount,

WritableByteChannel target)

throws IOException

{

if (!transferSupported)

return IOStatus.UNSUPPORTED;

FileDescriptor targetFD = null;

if (target instanceof FileChannelImpl) {

if (!fileSupported)

return IOStatus.UNSUPPORTED_CASE;

targetFD = ((FileChannelImpl)target).fd;

} else if (target instanceof SelChImpl) {

// Direct transfer to pipe causes EINVAL on some configurations

if ((target instanceof SinkChannelImpl) && !pipeSupported)

return IOStatus.UNSUPPORTED_CASE;

targetFD = ((SelChImpl)target).getFD();

}

if (targetFD == null)

return IOStatus.UNSUPPORTED;

int thisFDVal = IOUtil.fdVal(fd);

int targetFDVal = IOUtil.fdVal(targetFD);

if (thisFDVal == targetFDVal) // Not supported on some configurations

return IOStatus.UNSUPPORTED;

long n = -1;

int ti = -1;

try {

begin();

ti = threads.add();

if (!isOpen())

return -1;

do {

n = transferTo0(thisFDVal, position, icount, targetFDVal);

} while ((n == IOStatus.INTERRUPTED) && isOpen());

if (n == IOStatus.UNSUPPORTED_CASE) {

if (target instanceof SinkChannelImpl)

pipeSupported = false;

if (target instanceof FileChannelImpl)

fileSupported = false;

return IOStatus.UNSUPPORTED_CASE;

}

if (n == IOStatus.UNSUPPORTED) {

// Don't bother trying again

transferSupported = false;

return IOStatus.UNSUPPORTED;

}

return IOStatus.normalize(n);

} finally {

threads.remove(ti);

end (n > -1);

}

}

transferTo0()方法

// Transfers from src to dst, or returns -2 if kernel can't do that

private native long transferTo0(int src, long position, long count, int dst);

jni的 transferTo0()方法

JNIEXPORT jlong JNICALL

Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,

jint srcFD,

jlong position, jlong count,

jint dstFD)

{

#if defined(__linux__)

off64_t offset = (off64_t)position;

jlong n = sendfile64(dstFD, srcFD, &offset, (size_t)count);

if (n < 0) {

if (errno == EAGAIN)

return IOS_UNAVAILABLE;

if ((errno == EINVAL) && ((ssize_t)count >= 0))

return IOS_UNSUPPORTED_CASE;

if (errno == EINTR) {

return IOS_INTERRUPTED;

}

JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");

return IOS_THROWN;

}

return n;

#elif defined (__solaris__)

sendfilevec64_t sfv;

size_t numBytes = 0;

jlong result;

sfv.sfv_fd = srcFD;

sfv.sfv_flag = 0;

sfv.sfv_off = (off64_t)position;

sfv.sfv_len = count;

result = sendfilev64(dstFD, &sfv, 1, &numBytes);

/* Solaris sendfilev() will return -1 even if some bytes have been

* transferred, so we check numBytes first.

*/

if (numBytes > 0)

return numBytes;

if (result < 0) {

if (errno == EAGAIN)

return IOS_UNAVAILABLE;

if (errno == EOPNOTSUPP)

return IOS_UNSUPPORTED_CASE;

if ((errno == EINVAL) && ((ssize_t)count >= 0))

return IOS_UNSUPPORTED_CASE;

if (errno == EINTR)

return IOS_INTERRUPTED;

JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");

return IOS_THROWN;

}

return result;

#elif defined(__APPLE__)

off_t numBytes;

int result;

numBytes = count;

#ifdef __APPLE__

result = sendfile(srcFD, dstFD, position, &numBytes, NULL, 0);

#endif

if (numBytes > 0)

return numBytes;

if (result == -1) {

if (errno == EAGAIN)

return IOS_UNAVAILABLE;

if (errno == EOPNOTSUPP || errno == ENOTSOCK || errno == ENOTCONN)

return IOS_UNSUPPORTED_CASE;

if ((errno == EINVAL) && ((ssize_t)count >= 0))

return IOS_UNSUPPORTED_CASE;

if (errno == EINTR)

return IOS_INTERRUPTED;

JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");

return IOS_THROWN;

}

return result;

#else

return IOS_UNSUPPORTED_CASE;

#endif

}

底层是通过调用linux的sendFile()函数 或 sendFile64()函数 实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值