> 文档中心 > 使用FileChannel读取下载文件

使用FileChannel读取下载文件

使用FileChannel读取下载文件

  • 前言
  • 一、FileChannel是什么?
  • 二、FileChannal的方法介绍
    • 1.open
    • 2.read
    • 3.write
    • 4.lock()与tryLock()
  • 三、FileChannel下载网络图片
  • 总结
  • 参考链接

前言

FileChannal的理解和使用场景
对于文件的复制,平时我们都是使用输入输出流进行操作,利用源文件创建出一个输入流,然后利用目标文件创建出一个输出流,最后将输入流的数据读取写入到输出流中。这样也是可以进行操作的。但是利用fileChannel是很有用的一个方式。它能直接连接输入输出流的文件通道,将数据直接写入到目标文件中去。而且效率更高。
1.多线程情况下读取文件流
2.特定的大文件的读取等操作


一、FileChannel是什么?

FileChannel是通过创建channal 通道,操作一个文件。除了有读写操作之外,还有裁剪特定大小文件truncate(),强制在内存中的数据刷新到硬盘中去force(),对通道上锁lock()等功能

二、FileChannal的方法介绍

1.open

创建一个文件,并且返回一个channal,允许我们进入文件,对文件进行读写操作。

FileChannel.open(new File("D:\\hello.txt").toPath(), StandardOpenOption.CREATE_NEW);

StandardOpenOption 包含多种文件操作属性,比如:
READ(读),WRITE(写),SYNC/DSYNC (同步或异步IO)
当然,我们还可以通过FileOutputStream 文件流直接获取channal

File file=new File("D:\\hello.txt");FileOutputStream fileOutputStream = new FileOutputStream(file);FileChannel channel = fileOutputStream.getChannel();

2.read

代码如下(示例):

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//读取1024字节内容到byteBuffer钟fileChannel.read(byteBuffer);

3.write

代码如下(示例):

//写数据到channelfileChannelOutput.write(byteBuffer);

4.lock()与tryLock()

lock()与tryLock()方法都是尝试去获取在某一文件上的独有锁(以下简称独有锁),可以实现进程间操作的互斥。区别在于lock()会阻塞(blocking)方法的执行,tryLock()则不会。
测试代码:

private void processLockTest() {    try { File file = new File(getFilesDir().getAbsolutePath() + File.separator + "lock.lock"); FileOutputStream fos = new FileOutputStream(file); FileLock fl = null; boolean loop = true; int time = 0; LogUtil.log(android.os.Process.myPid() + "   " + "while start" + "  " + file.getAbsolutePath()); while (loop) {     time++;     LogUtil.log(android.os.Process.myPid() + "   " + "loop 次数:" + time);     if (fl == null) {  LogUtil.log(android.os.Process.myPid() + "   " + "tryLock before" + " " + file.getAbsolutePath());  try {      fl = fos.getChannel().tryLock();  } catch (Exception e) {      e.printStackTrace();      LogUtil.log(android.os.Process.myPid() + "   " + "tryLock IOException" + " " + e.toString());  }  LogUtil.log(android.os.Process.myPid() + "   " + "tryLock after" + " " + file.getAbsolutePath());     }     if (fl != null) {  while (loop) {      Thread.sleep(2000);      time++;      if (time == 5) {   fl.release();      }      if (time == 10) {   loop = false;      }      if (fl != null) {   LogUtil.log(System.currentTimeMillis() + "  " + android.os.Process.myPid() + "  " + "got");      } else {   LogUtil.log(System.currentTimeMillis() + "  " + android.os.Process.myPid() + "  " + "fl is null");      }  }     } else {  LogUtil.log(System.currentTimeMillis() + "  " + android.os.Process.myPid() + "  " + "ungot");     }     Thread.sleep(2000); } LogUtil.log(android.os.Process.myPid() + "   " + "while over");    } catch (Throwable t) {     }}

三、FileChannel下载网络图片

该处使用的url网络请求的数据。

 /**     *      * @param uri 网络图片地址     * @param filePath 下载目录     * @param fileName 下载文件名     */    public static void downLoadImage(String uri, String filePath,String fileName) { ReadableByteChannel readableByteChannel = null; FileChannel fileChannel = null; File file; URL url; FileOutputStream fileOutputStream = null; try {     url = new URL(uri);     //首先从 URL stream 中创建一个 ReadableByteChannel 来读取网络文件     readableByteChannel = Channels.newChannel(url.openStream());     String path = filePath + fileName;     file = new File(path);     if (!file.getParentFile().exists() && !file.getParentFile().isDirectory()) {  file.getParentFile().mkdirs();     }     //通过 ReadableByteChannel 读取到的字节会流动到一个 FileChannel 中,然后再关联一个本地文件进行下载操作     fileOutputStream = new FileOutputStream(file);     fileChannel = fileOutputStream.getChannel();     //最后用 transferFrom()方法就可以把 ReadableByteChannel 获取到的字节写入本地文件     fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE); } catch (Exception e) {     e.printStackTrace(); } finally {     try {  if (null != readableByteChannel) {      readableByteChannel.close();  }  if (null != fileChannel) {      fileChannel.close();  }  if (null != fileOutputStream) {      fileOutputStream.close();  }     } catch (IOException e) {  e.printStackTrace();     } }    }

测试下载图片

    public static void main(String[] args) throws IOException { String fileUrl = "https://img.pconline.com.cn/images/upload/upc/tx/itbbs/1308/16/c8/24543026_1376637095791_mthumb.jpg"; downLoadImage(fileUrl,"D:/test/","hello.jpg");    }

总结

利用filechannel使用的时间比普通的读取输入时间缩短了将近一半。尤其是在进行大文件复制的时候,filechannel显得更加有优势

参考链接

链接:
Java之FileChannel类的理解和使用.姚镜堂
ava之FileChannel类的理解和使用 -----java 流NIO的使用.fight_man001