有这样一个方法,使用MappedByteBuffer来拷贝文件
如下: private static final int BUFFER_SIZE = 8 * 1024;
/**
* 将源文件拷贝一份到目的文件中
* @param src 源文件
* @param des 目的文件
* @throws Exception IO异常
*/
public static void fastCopyFile( File src, File des ) throws Exception {
RandomAccessFile raf1 = new RandomAccessFile(src, "rw");
RandomAccessFile raf2 = new RandomAccessFile(des, "rw");
FileChannel fcIn = raf1.getChannel();
FileChannel fcOut = raf2.getChannel();
long len = src.length();
long index = 1;
MappedByteBuffer mappedByteBuffer = null ;
while( true ){
/** 如果最后一次读写不足8K,则取文件长度 */
long l = index * BUFFER_SIZE;
if( l >= len ){
l = len ;
}
/** 映射文件部分内容到内存中 */
mappedByteBuffer = fcIn.map(FileChannel.MapMode.READ_WRITE, (index - 1) * BUFFER_SIZE, l);
fcIn.read(mappedByteBuffer);
/** 写入到目标文件中 */
mappedByteBuffer.flip();
fcOut.write(mappedByteBuffer);
/** 判断文件是否读写完毕 */
if( l == len ) { break; }
index ++;
/** 清空mappedByteBuffer */
mappedByteBuffer.clear();
//mappedByteBuffer = null;
}
/** 回收资源 */
mappedByteBuffer.clear();
fcOut.close();
fcIn.close();
raf2.close();
raf1.close();
}先说一下我的测试情况:
测试拷贝的文件为一步名为《后天》的电影,大小约594M。
电脑系统为XP,CPU为Pentium T4300,2.10GHZ。内存2G。
有几个问题想请教一下:
1.FileChannel.map这个方法应该是将此FileChannel连接的文件的一部分映射到MappedByteBuffer中,在上面的程序也就是映射8K的数据到mappedByteChannel中,但为什么程序一运行起来,消耗的内存一直疯长?一直超过594M,然后拷贝结束后,报了一个异常,我试过拷贝的文件,可以播放,里面的数据是没有问题的。异常情况如下:Exception in thread "main" java.io.IOException: Map failed
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:761)
at com.nio.example.FastCopyFile.fastCopyFile(FastCopyFile.java:68)
at com.nio.example.FastCopyFile.main(FastCopyFile.java:28)
Caused by: java.lang.OutOfMemoryError: Map failed
at sun.nio.ch.FileChannelImpl.map0(Native Method)
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:758)
... 2 more为什么会报异常?为什么内存一直疯长?
2.FileChannel.map这个方法调用之后mappedByteBuffer中间是不是已经有了文件中的数据了?为什么还需要fcIn.read(mappedByteBuffer);一次?
3.怎么关掉这个mappedByteBuffer?mappedByteBuffer = null它报异常。
如下: private static final int BUFFER_SIZE = 8 * 1024;
/**
* 将源文件拷贝一份到目的文件中
* @param src 源文件
* @param des 目的文件
* @throws Exception IO异常
*/
public static void fastCopyFile( File src, File des ) throws Exception {
RandomAccessFile raf1 = new RandomAccessFile(src, "rw");
RandomAccessFile raf2 = new RandomAccessFile(des, "rw");
FileChannel fcIn = raf1.getChannel();
FileChannel fcOut = raf2.getChannel();
long len = src.length();
long index = 1;
MappedByteBuffer mappedByteBuffer = null ;
while( true ){
/** 如果最后一次读写不足8K,则取文件长度 */
long l = index * BUFFER_SIZE;
if( l >= len ){
l = len ;
}
/** 映射文件部分内容到内存中 */
mappedByteBuffer = fcIn.map(FileChannel.MapMode.READ_WRITE, (index - 1) * BUFFER_SIZE, l);
fcIn.read(mappedByteBuffer);
/** 写入到目标文件中 */
mappedByteBuffer.flip();
fcOut.write(mappedByteBuffer);
/** 判断文件是否读写完毕 */
if( l == len ) { break; }
index ++;
/** 清空mappedByteBuffer */
mappedByteBuffer.clear();
//mappedByteBuffer = null;
}
/** 回收资源 */
mappedByteBuffer.clear();
fcOut.close();
fcIn.close();
raf2.close();
raf1.close();
}先说一下我的测试情况:
测试拷贝的文件为一步名为《后天》的电影,大小约594M。
电脑系统为XP,CPU为Pentium T4300,2.10GHZ。内存2G。
有几个问题想请教一下:
1.FileChannel.map这个方法应该是将此FileChannel连接的文件的一部分映射到MappedByteBuffer中,在上面的程序也就是映射8K的数据到mappedByteChannel中,但为什么程序一运行起来,消耗的内存一直疯长?一直超过594M,然后拷贝结束后,报了一个异常,我试过拷贝的文件,可以播放,里面的数据是没有问题的。异常情况如下:Exception in thread "main" java.io.IOException: Map failed
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:761)
at com.nio.example.FastCopyFile.fastCopyFile(FastCopyFile.java:68)
at com.nio.example.FastCopyFile.main(FastCopyFile.java:28)
Caused by: java.lang.OutOfMemoryError: Map failed
at sun.nio.ch.FileChannelImpl.map0(Native Method)
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:758)
... 2 more为什么会报异常?为什么内存一直疯长?
2.FileChannel.map这个方法调用之后mappedByteBuffer中间是不是已经有了文件中的数据了?为什么还需要fcIn.read(mappedByteBuffer);一次?
3.怎么关掉这个mappedByteBuffer?mappedByteBuffer = null它报异常。
就像这样:fcIn.transferTo(0, src.length(), fcOut);
FileChannel srcChannel = new FileInputStream("srcfile").getChannel();
FileChannel destChannel = new FileOutputStream("destfile").getChannel(); destChannel.transferFrom(srcChannel, 0, srcChannel.size());
srcChannel.close();
destChannel.close();
} catch (IOException e){
...
}
len = 594 * 1024 * 1024 = 623265457字节。
但程序中的l = 1990656时,拷贝的文件就已经达到了243M,应该是这样的 l = 243 * 1024 * 8 = 1990656
,这样就造成了条件 l > len几乎是不可能满足的,这是为什么呢?l的单位到底是什么呢?
,程序应该还是读取文件到文件尾然后再给buffer
while循环里面没有什么需要关闭的,clear其实并没有将Buffer的内容清空,只是把position=0,limite=capacity
= -1
while循环出来再把相应的流和通道关闭就行了
RandomAccessFile raf1 = new RandomAccessFile(src, "r");
RandomAccessFile raf2 = new RandomAccessFile(des, "rw");
FileChannel fcIn = raf1.getChannel();
FileChannel fcOut = raf2.getChannel();
long len = src.length();
long index = 1;
MappedByteBuffer mappedByteBuffer = null ;
boolean isFinished = false;
while( true ){
/** 如果最后一次读写不足8K,则取文件长度 */
long begin = (index - 1) * BUFFER_SIZE;
long length = BUFFER_SIZE;
if( (begin + length)>= len ){
isFinished = true;
length = len - begin ;
}
/** 映射文件部分内容到内存中 */
mappedByteBuffer = fcIn.map(FileChannel.MapMode.READ_ONLY, begin, length);
/** 写入到目标文件中 */
fcOut.write(mappedByteBuffer);
/** 判断文件是否读写完毕 */
if( isFinished ) { break; }
index ++;
/** 清空mappedByteBuffer */
mappedByteBuffer.clear();
}
/** 回收资源 */
mappedByteBuffer.clear();
fcOut.close();
fcIn.close();
raf2.close();
raf1.close();
}