使用nio进行并行文件下载,而无需为每个文件下载创建线程 我曾经尝试过一个程序,该程序使用java.nio通过为每个文件下载创建一个线程来并行下载文件。 包com.java.tftp.nio; 导入java.io.File; 导入java.io.FileN
使用nio进行并行文件下载,而无需为每个文件下载创建线程使用nio进行并行文件下载,而无需为每个文件下载创建线程 我曾经尝试过一个程序,该程序使用java.nio通过为每个文件下载创建一个线程来并行下载文件。 包com.java.tftp.nio; 导入java.io.File; 导入java.io.FileN,java,io,nio,java.util.concurrent,Java,Io,Nio,Java.util.concurrent,使用nio进行并行文件下载,而无需为每个文件下载创建线程 我曾经尝试过一个程序,该程序使用java.nio通过为每个文件下载创建一个线程来并行下载文件。 包com.java.tftp.nio; 导入java.io.File; 导入java.io.FileNotFoundException; 导入java.io.FileOutputStream; 导入java.io.IOException; 导入java.io.OutputStream; 导入java.net.InetSocketAddress;
我曾经尝试过一个程序,该程序使用java.nio通过为每个文件下载创建一个线程来并行下载文件。
包com.java.tftp.nio;
导入java.io.File;
导入java.io.FileNotFoundException;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.io.OutputStream;
导入java.net.InetSocketAddress;
导入java.net.SocketAddress;
导入java.nio.ByteBuffer;
导入java.nio.channels.DatagramChannel;
导入java.nio.channels.SelectionKey;
导入java.nio.channels.Selector;
导入java.util.Iterator;
导入java.util.List;
导入java.util.Set;
/**
*此类用于通过从tftp服务器并发下载文件
*正在配置文件名,文件数为。
*
*@author shirram
*
*/
公共类TFTP_NIO_客户端{
/**
*目标文件夹
* */
私有字符串destinationFolder;
/**
*要下载的文件名列表
* */
私有列表文件名;
/**
*整数表示要同时下载的文件数
* */
私家车内无办公室下载;
公共TFTP_NIO_客户端(列出文件名、字符串目标文件夹、,
int noOfFilesToDownload){
this.destinationFolder=destinationFolder;
this.fileNames=文件名;
this.noOfFilesToDownload=noOfFilesToDownload;
初始化handlers();
}
/**
*此方法创建线程以注册要处理下载的通道
*同时存档。
*
*@param nooffilestownload
*-要下载的文件数
*/
私有void初始化句柄(){
对于(int i=0;i字节数组中的文件名。0->表示文件模式结束
*->字节数组“netascii”或“octet”中的字符串
*
*@param aOpcode
*@param-aMode
*@param aFileName
*@抛出异常
*/
私有void sendRequest(int aOpcode、int aMode、字符串aFileName、,
DatagramChannel aChannel,InetSocketAddress aaAddress)
抛出IOException{
//读取请求包
tftpresequestpacket theRequestPacket=新的tftpresequestpacket();
阿查内尔·森德(
TheRequestPackage.ConstructReadRequestPackage(文件名,aMode),
a地址);
}
/**
*发送TFTP ACK数据包:|操作码|块#|操作码->4->2字节
*块->块编号->2字节
*
*@param-aBlock
*/
专用ByteBuffer发送包(int aBlockNumber){
//确认包
TFTPAckPacket theAckPacket=新的TFTPAckPacket();
返回ackpacket.getTFTPAckPacket(一个锁号);
}
/**
*此类用于处理来自服务器的并发下载。
*
* */
公共类SelectorHandler扩展线程{
专用选择器;
私有字符串文件名;
/**
*指示文件完成的标志。
* */
私有布尔值isFileReadFinished=false;
公共选择器处理程序(选择器A选择器,字符串A文件名)
抛出IOException{
this.selector=a选择器;
this.fileName=aFileName;
寄存器通道();
}
私有无效注册表通道()引发IOException{
DatagramChannel theChannel=DatagramChannel.open();
信道配置阻塞(假);
selector.wakeup();
通道寄存器(选择器、选择键、操作读取);
sendRequest(Constants.OP_读取、Constants.ASCII_模式、文件名、,
通道,新的InetSocketAddress(Constants.HOST,
常数(TFTP_端口);
}
@凌驾
公开募捐{
过程();
}
私有无效进程(){
System.out.println(“开始下载“+fileName+”);
File theFile=新文件(目标文件夹
+fileName.substring(fileName.lastIndexOf(“/”);
FileOutputStream offout=null;
试一试{
offout=新文件输出流(theFile);
}catch(filenotfounde异常){
e、 printStackTrace();
}
而(!isFileReadFinished){
试一试{
if(selector.select()==0){
试一试{
//引入sleep 2sec是因为选择器是
//线程安全,但密钥不是线程安全的
《睡眠》(2000年);
}捕捉(中断异常e){
继续;
}
继续;
}
设置Set=selector.selectedKeys();
迭代器theSelectedKeys=theSet.Iterator();
已同步(选定键){
while(SelectedKeys.hasNext()){
SelectionKey theKey=theSelectedKeys.next();
选择的键。删除();
if(key.isReadable()){
isFileReadFinished=read(键,offout,
文件名);
如果(!isFileReadFinished){
key.interesttops(选择key.OP_READ);
}
I have tried a program which download files parallely using java.nio by creating a thread per file download.
package com.java.tftp.nio;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* This class is used to download files concurrently from tftp server by
* configuring the filenames, no of files.
*
* @author SHRIRAM
*
*/
public class TFTP_NIO_Client {
/**
* destination folder
* */
private String destinationFolder;
/**
* list of files names to download
* */
private List<String> fileNames;
/**
* integer indicates the number of files to download concurrently
* */
private int noOfFilesToDownload;
public TFTP_NIO_Client(List<String> fileNames, String destinationFolder,
int noOfFilesToDownload) {
this.destinationFolder = destinationFolder;
this.fileNames = fileNames;
this.noOfFilesToDownload = noOfFilesToDownload;
initializeHandlers();
}
/**
* This method creates threads to register the channel to process download
* files concurrently.
*
* @param noOfFilesToDownload
* - no of files to download
*/
private void initializeHandlers() {
for (int i = 0; i < noOfFilesToDownload; i++) {
try {
Selector aSelector = Selector.open();
SelectorHandler theSelectionHandler = new SelectorHandler(
aSelector, fileNames.get(i));
theSelectionHandler.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Setup RRQ/WRQ packet Packet : | Opcode | FileName | 0 | mode | 0 |
* Filename -> Filename in array of bytes. 0 -> indicates end of file mode
* -> string in byte array 'netascii' or 'octet'
*
* @param aOpcode
* @param aMode
* @param aFileName
* @throws IOException
*/
private void sendRequest(int aOpcode, int aMode, String aFileName,
DatagramChannel aChannel, InetSocketAddress aAddress)
throws IOException {
// Read request packet
TFTPReadRequestPacket theRequestPacket = new TFTPReadRequestPacket();
aChannel.send(
theRequestPacket.constructReadRequestPacket(aFileName, aMode),
aAddress);
}
/**
* sends TFTP ACK Packet Packet : | opcode | Block# | opcode -> 4 -> 2 bytes
* Block -> block number -> 2bytes
*
* @param aBlock
*/
private ByteBuffer sendAckPacket(int aBlockNumber) {
// acknowledge packet
TFTPAckPacket theAckPacket = new TFTPAckPacket();
return theAckPacket.getTFTPAckPacket(aBlockNumber);
}
/**
* This class is used to handle concurrent downloads from the server.
*
* */
public class SelectorHandler extends Thread {
private Selector selector;
private String fileName;
/**
* flag to indicate the file completion.
* */
private boolean isFileReadFinished = false;
public SelectorHandler(Selector aSelector, String aFileName)
throws IOException {
this.selector = aSelector;
this.fileName = aFileName;
registerChannel();
}
private void registerChannel() throws IOException {
DatagramChannel theChannel = DatagramChannel.open();
theChannel.configureBlocking(false);
selector.wakeup();
theChannel.register(selector, SelectionKey.OP_READ);
sendRequest(Constants.OP_READ, Constants.ASCII_MODE, fileName,
theChannel, new InetSocketAddress(Constants.HOST,
Constants.TFTP_PORT));
}
@Override
public void run() {
process();
}
private void process() {
System.out.println("Download started for " + fileName + " ");
File theFile = new File(destinationFolder
+ fileName.substring(fileName.lastIndexOf("/")));
FileOutputStream theFout = null;
try {
theFout = new FileOutputStream(theFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (!isFileReadFinished) {
try {
if (selector.select() == 0) {
try {
// sleep 2sec was introduced because selector is
// thread safe but keys are not thread safe
Thread.sleep(2000);
} catch (InterruptedException e) {
continue;
}
continue;
}
Set<SelectionKey> theSet = selector.selectedKeys();
Iterator<SelectionKey> theSelectedKeys = theSet.iterator();
synchronized (theSelectedKeys) {
while (theSelectedKeys.hasNext()) {
SelectionKey theKey = theSelectedKeys.next();
theSelectedKeys.remove();
if (theKey.isReadable()) {
isFileReadFinished = read(theKey, theFout,
fileName);
if (!isFileReadFinished) {
theKey.interestOps(SelectionKey.OP_READ);
}
} else if (theKey.isWritable()) {
// there is no implementation for file write to
// server.
theKey.interestOps(SelectionKey.OP_READ);
}
}
}
} catch (IOException ie) {
ie.printStackTrace();
}
}
System.out.println("Download finished for " + fileName);
try {
if (selector.isOpen()) {
selector.close();
}
if (theFout != null) {
theFout.close();
}
} catch (IOException ie) {
}
}
}
/**
* @param aKey
* registered key for the selector
* @param aOutStream
* - file output stream to write the file contents.
* @return boolean
* @throws IOException
*/
private boolean read(SelectionKey aKey, OutputStream aOutStream,
String aFileName) throws IOException {
DatagramChannel theChannel = (DatagramChannel) aKey.channel();
// data packet
TFTPDataPacket theDataPacket = new TFTPDataPacket();
ByteBuffer theReceivedBuffer = theDataPacket.constructTFTPDataPacket();
SocketAddress theSocketAddress = theChannel.receive(theReceivedBuffer);
theReceivedBuffer.flip();
byte[] theBuffer = theReceivedBuffer.array();
byte[] theDataBuffer = theDataPacket.getDataBlock();
if (theDataPacket.getOpCode() == Constants.OP_DATA) {
int theLimit = theDataPacket.getLimit();
// checks the limit of the buffer because a packet with data less
// than 512 bytes of content signals that it is the last packet in
// transmission for this particular file
if (theLimit != Constants.MAX_BUFFER_SIZE
&& theLimit < Constants.MAX_BUFFER_SIZE) {
byte[] theLastBlock = new byte[theLimit];
System.arraycopy(theBuffer, 0, theLastBlock, 0, theLimit);
// writes the lastblock
aOutStream.write(theLastBlock);
// sends an acknowledgment to the server using TFTP packet
// block number
theChannel
.send(sendAckPacket((((theBuffer[2] & 0xff) << 8) | (theBuffer[3] & 0xff))),
theSocketAddress);
if (theChannel.isOpen()) {
theChannel.close();
}
return true;
} else {
aOutStream.write(theDataBuffer);
// sends an acknowledgment to the server using TFTP packet
// block number
theChannel
.send(sendAckPacket((((theBuffer[2] & 0xff) << 8) | (theBuffer[3] & 0xff))),
theSocketAddress);
return false;
}
} else if (Integer.valueOf(theBuffer[1]) == Constants.OP_ERROR) {
System.out.println("File : " + aFileName + " not found ");
handleError(theReceivedBuffer);
}
return false;
}
/**
* This method handles the error packet received from Server.
*
* @param aBuffer
*/
private void handleError(ByteBuffer aBuffer) {
// Error packet
new TFTPErrorPacket(aBuffer);
}
}
Is it possible to download multiple files in parallel using java.nio by not creating a thread per file download? If yes can anybody suggest a solution to proceed further.