MINA転送ファイル名

10943 ワード

ネット上で資料の山を調べたが,転送ファイルの名前はみな死んでしまった.では、ファイルとファイル名を同時に転送するにはどうすればいいですか?これはMinaの符号化と復号化に使います.minaに触れたばかりの頃、このpdf Apache_を見てみましょう.Mina_Server_2.0中国語参考マニュアルV 1.0.pdfというドキュメントは最初は文字列を簡単に転送できますが、ファイルを転送するのはちょっと難しいです.
符号化と復号化について直接説明します.
package com.blazefire.client;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

import com.blazefire.bean.BaseMessage;
import com.blazefire.bean.FileBean;
import com.blazefire.util.BeanUtil;
import com.blazefire.util.FileHelper;

public class ClientHandler extends IoHandlerAdapter{
	
	/**
	 *  
	 * */
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		// TODO Auto-generated method stub
		super.messageReceived(session, message);
		
	}

	public void sessionOpened(IoSession session) { 
		BaseMessage baseMessage = new BaseMessage();
		baseMessage.setDataType(BeanUtil.UPLOAD_FILE);
		FileBean bean = new FileBean();
		File file = new File("e:\\ .jpg");
		bean.setFileName(file.getName());
		bean.setFileSize((int)file.length());
		try {
			FileHelper helper =new FileHelper();
			bean.setFileContent(helper.getContent(file));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		baseMessage.setData(bean);
		session.write(baseMessage); 
	}

	public void sessionCreated(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		super.sessionCreated(session);
	}
	
	
}

接続に成功した後、sessionOpenedメソッドを呼び出し、ローカルファイルを読み取り、サーバにファイルを転送します.このうち、使用するクラスの一部は記事の末尾に貼り付けられます.
ファイルを転送するにはファイル名、ファイルサイズ、ファイルbyte配列が必要です.ファイル名はもちろん、ファイルサイズは復号するためにどのバイトが読み込まれたかを知るために停止します.ファイルbyte配列はファイル内容を格納する
BaseMessage baseMessage = new BaseMessage();
baseMessage.setDataType(BeanUtil.UPLOAD_FILE);//BeanUtil.UPLOAD_FILE 1
これらの情報を準備した後、sessionを呼び出す.writeメソッドは符号化を開始する.
package com.blazefire.util;

import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.MessageEncoder;

import com.blazefire.bean.BaseMessage;
import com.blazefire.bean.FileBean;

public class BaseMessageEncoder implements MessageEncoder<BaseMessage> {

	/**
	 *  
	 * */
	public void encode(IoSession session, BaseMessage message,ProtocolEncoderOutput outPut) throws Exception {
		// TODO Auto-generated method stub
		IoBuffer buffer = IoBuffer.allocate(1024*1024*50); 
		buffer.putInt(message.getDataType());
		FileBean bean = (FileBean) message.getData();
		byte[] byteStr = bean.getFileName().getBytes(BeanUtil.charset);
		buffer.putInt(byteStr.length);
		buffer.putInt(bean.getFileSize());
		buffer.put(byteStr);
		buffer.put(bean.getFileContent());
		buffer.flip();
		outPut.write(buffer);
		System.out.println(" !");
	}

}
buffer.putInt(message.getDataType());まずint値1を1つ入れてこの値を入れたのは,主にこの項目で複数のデコーダを用い,異なる情報に対して異なる符号化を行い,復号する際にこのパラメータに基づいてこのデコーダで復号するか否かを判断するためである.
byte[] byteStr = bean.getFileName().getBytes(BeanUtil.charset); 文字列をbyte配列に変換するBeanUtil.charset   Charset charset = Charset.forName("utf-8"); utf-8符号化
buffer.putInt(byteStr.length); ファイル名のbyte配列長bufferを記録する.putInt(bean.getFileSize()); レコードファイルのbyte配列長
buffer.put(byteStr); buffer bufferに格納する.put(bean.getFileContent());bufferに格納
コードはこれで終わります.
サーバの復号化を開始します.
package com.blazefire.util;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;

import com.blazefire.bean.BaseMessage;
import com.blazefire.bean.FileBean;

public class BaseMessageDecoder  implements MessageDecoder {
	private AttributeKey CONTEXT = new AttributeKey(getClass(), "context");
	/**
	 *  
	 * */
	public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
		// TODO Auto-generated method stub
		Context context = (Context) session.getAttribute(CONTEXT);
		if(context == null){
			context = new Context();
			context.dataType = in.getInt();
			if(context.dataType == BeanUtil.UPLOAD_FILE){
				context.strLength = in.getInt();
				context.byteStr = new byte[context.strLength];
				context.fileSize = in.getInt();
				context.byteFile = new byte[context.fileSize];
				session.setAttribute(CONTEXT, context);
				return MessageDecoderResult.OK;
			}else{
				return MessageDecoderResult.NOT_OK;
			}
		}else{
			if(context.dataType == BeanUtil.UPLOAD_FILE){
				return MessageDecoderResult.OK;
			}else{
				return MessageDecoderResult.NOT_OK;
			}
		}
	}

	/**
	 *  
	 * */
	public MessageDecoderResult decode(IoSession session, IoBuffer in,
			ProtocolDecoderOutput outPut) throws Exception {
		// TODO Auto-generated method stub
		System.out.println(" :");
		Context context = (Context) session.getAttribute(CONTEXT);
		if(!context.init){
			context.init = true;
			in.getInt();
			in.getInt();
			in.getInt();
		}
		byte[] byteFile = context.byteFile;
		int count = context.count;
		while(in.hasRemaining()){
			byte b = in.get();
			if(!context.isReadName){
				context.byteStr[count] = b;
				if(count == context.strLength-1){
					context.fileName = new String(context.byteStr,BeanUtil.charset);
					System.out.println(context.fileName);
					count = -1;
					context.isReadName = true;
				}
			}
			if(context.isReadName && count != -1){
				byteFile[count] = b;
			}
		//	byteFile[count] = b;
			count++;
		}
		context.count = count;
		System.out.println("count:"+count);
		System.out.println("context.fileSize:"+context.fileSize);
		session.setAttribute(CONTEXT, context);
		if(context.count == context.fileSize){
			BaseMessage message = new BaseMessage();
			message.setDataType(context.dataType);
			FileBean bean = new FileBean();
			bean.setFileName(context.fileName);
			bean.setFileSize(context.fileSize);
			bean.setFileContent(context.byteFile);
			message.setData(bean);
			outPut.write(message);
			context.reset();
		}
		return MessageDecoderResult.OK;
	}

	/**
	 * 
	 * */
	public void finishDecode(IoSession session, ProtocolDecoderOutput outPut)
			throws Exception {
		// TODO Auto-generated method stub
		System.out.println("end:::::::::::::::::");
	}
	private class Context{
		public int dataType;
		public byte[] byteFile;
		public int count;
		public int strLength;
		public boolean isReadName;
		public int fileSize;
		public byte[] byteStr;
		public String fileName;
		public boolean init = false;
		
		public void reset(){
			dataType = 0;
			byteFile = null;
			count = 0;
			strLength = 0;
			isReadName = false;
			fileSize = 0;
			byteStr = null;
			fileName = null;
			
		}
	}


}
decodableメソッドは、現在のデコーダを使用するかどうかを判断することです.
このCumulativeProtocolDecoderデコーダのいくつかの紹介と使用、特に複雑なデコーダの説明を見たことがあります.
なぜここでCONTEXTという属性が使われているのかがわかります.コードするとき、ファイルの内容が長く、多くのパケットに分かれているので、このとき復号するときはそのバイトまで復号する必要があります.次に復号するときはこのバイトから始めます.
ここで注意すべき点は、現在のデコーダが実装しているのはMessageDecoderというインタフェースである.pdfのデコーダはCumulativeProtocolDecoderというクラスを継承している.
CumulativeProtocolDecoderクラスはdoDecodeメソッドでdoDecodeメソッドを呼び出し続ける必要があるかどうかを自分で判断する必要があります.データ復号が必要な場合、この戻り値はtrueであり、復号が完了するとfalseに直接戻る.
MessageDecoderというインタフェースは自分で判断する必要はありません
このクラスは自分で呼び出してデータを転送するので、毎回このクラスのメソッドを呼び出し、毎回メンバー変数を初期化します.
復号というのは主に複数のパケットの復号を解決して1本の完成したメッセージをつなぎ合わせて、この問題が解決して、何の難題もありません.
if(!context.init){
			context.init = true;
			in.getInt();
			in.getInt();
			in.getInt();
		}

これを加えると、入力された整数バイトが読み出され、ファイル名のバイトとファイルバイトしか残っていません.
読み取りが終わったら、contextの値をリセットしてください.そうしないと、後続のファイルの読み取りに影響します.
これらを処理したら、直接ファイルを書きます.
package com.blazefire.server;

import java.io.FileOutputStream;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

import com.blazefire.bean.BaseMessage;
import com.blazefire.bean.FileBean;

public class ServerHandler extends IoHandlerAdapter{


	public void sessionCreated(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		super.sessionCreated(session);
	}

	public void sessionOpened(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		super.sessionOpened(session);
	}
	/**
	 *  
	 * */
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		// TODO Auto-generated method stub
		super.messageReceived(session, message);
		System.out.println("==============");
		BaseMessage baseMessage = (BaseMessage) message;
		FileBean bean = (FileBean) baseMessage.getData();
		System.out.println(bean.getFileName());
		FileOutputStream os = new FileOutputStream("f:\\"+bean.getFileName());
		os.write(bean.getFileContent());
		os.close();
	}


	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		// TODO Auto-generated method stub
		super.exceptionCaught(session, cause);
	}
}

minaは最初は符号化復号にもあまり詳しくなかったが、その後も他の人のコードに基づいて、自分でテストしてやっとこのバージョンが出た.みんなに自分で作ってもらいたいだけなので、もっと深く理解することができます.皆さんの都合上、ソースを貼っておきましょう.
ソースのダウンロード