以下是使用NIO读写文件的demo
package com.example.demo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class DealMediaDownload {
static String txtUrl = "C:/Users/admin/Desktop/upFile/123.txt";
static String saveTxtFile = "C:/Users/admin/Desktop/upFile/1213.txt";
static String mediaUrl="C:/Users/admin/Desktop/upFile/1.mp4";
static String saveMediaFile="C:/Users/admin/Desktop/upFile/11.mp4";
public static void main(String[] args) {
//ReadNIO(mediaUrl,saveMediaFile);
ReadWriteNIO(txtUrl,saveTxtFile);
}
private static void ReadWriteNIO(String url,String targetUrl) {
try (FileInputStream fis = new FileInputStream(url);
FileOutputStream fos =new FileOutputStream(targetUrl,true); //true 是使得写入文件时不进行覆盖,而是追加内容
FileChannel fi = fis.getChannel();
FileChannel fo = fos.getChannel();
){
ByteBuffer bb = ByteBuffer.allocate(1024);
System.out.println("限制是: " + bb.limit() + ", 容量是: " + bb.capacity() + ", 位置是: " + bb.position());
int length =0;
int i=0;
/**
* 1.fi.read(bb) 通道读取文件数据存放到buffer缓存区中
* 2.bb.flip() 将缓冲区从写模式切换到读模式,主要是实现缓存区的指针位置从1023位回复到0位,以便从头开始读
* 3.fo.write(bb) 通道从buffer缓存区中读取数据写入到文件
* 4.bb.clear() 从读模式切换到写模式,不会清空数据,但后续写数据会覆盖原来的数据,即使有部分数据没有读,也会被遗忘;
* 5. bb.compact() 从读数据切换到写模式,不会清空数据,会将所有未读的数据copy到缓冲区头部,后续写数据不会覆盖,而是在这些数据之后写数据
* **注:byteBuffer属性有 position,limit,capacity,在写入数据,比如写入10个长度的数据,position和limit值为10,capacity不变,使用flip()方法能使的postion=0,但是limit不改变,当从缓存区读取时,每次读取到limit的位置就结束了,无法充分利用整个缓存区,当读写使用同一个缓存区时,在写入数据后需调用clear()方法,清楚调limit的限制。**
*/
while((length=fi.read(bb))!=-1) {
bb.flip();
fo.write(bb);
bb.compact();
i++;
}
System.out.println("循环次数:"+i);
System.out.println("完成");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.这一步其实是当我们刚开始初始化这个buffer数组的时候,开始默认是这样的
2、但是当你往buffer数组中开始写入的时候几个字节的时候就会变成下面的图,position会移动你数据的结束的下一个位置,这个时候你需要把buffer中的数据写到channel管道中,所以此时我们就需要用这个buffer.flip();方法,
3、当你调用完2中的方法时,这个时候就会变成下面的图了,这样的话其实就可以知道你刚刚写到buffer中的数据是在position—->limit之间,然后下一步调用clear();
4、这时底层操作系统就可以从缓冲区中正确读取这 5 个字节数据发送出去了。在下一次写数据之前我们在调一下 clear() 方法。缓冲区的索引状态又回到初始位置。(其实这一步有点像IO中的把转运字节数组 char[] buf = new char[1024]; 不足1024字节的部分给强制刷新出去的意思)
以下是NIO读取网络视频的demo(已修正可用)
public static void httpDownload(String httpUrl, String saveFile) {
try (FileOutputStream fos =new FileOutputStream(saveFile,false);
FileChannel fi = fos.getChannel();){
URL url = new URL(httpUrl);
URLConnection conn = url.openConnection();
conn.connect();
ByteBuffer bb = ByteBuffer.allocate(2048);
InputStream is = conn.getInputStream();
int byteRead;
//BufferedInputStream bis = new BufferedInputStream(is);
byte[] b = new byte[2048];
int j = 0;
while((byteRead=is.read(b))!=-1) {
System.out.print(b[2047]+",");
//注:可能是视频的缘故,不允许有多的空数据,在put的时候需要指定数组是从start到end,防止空数据
//不然下载的视频无法播放
bb.put(b,0,byteRead);
bb.flip();
fi.write(bb);
bb.clear();
j++;
}
System.out.println("循环次数:"+j);
fos.flush();
System.out.println("done!");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
以下是用IO读写视频
public static void httpDownload(String httpUrl, String saveFile) {
// 1.下载网络文件
try {
long start = System.currentTimeMillis();
int byteRead;
URL url= new URL(httpUrl);
//2.获取链接
URLConnection conn = url.openConnection();
//3.输入流
InputStream inStream = conn.getInputStream();
//3.写入文件
FileOutputStream fs = new FileOutputStream(saveFile);
byte[] buffer = new byte[2048];
int i=0;
while ((byteRead = inStream.read(buffer)) != -1) {
System.out.print(buffer[2047]+",");
fs.write(buffer, 0, byteRead);
i++;
}
System.out.println("循环次数:"+i);
inStream.close();
fs.close();
System.out.println("完成");
} catch (IOException e) {
e.printStackTrace();
System.out.println("失败");
}
}