`

Java Socket 02- 常识篇之文件传送

阅读更多

    清明节放完假刚回来,马上进入到写博文的节奏,今天继续来学习关于传统的Socket编程 - 客户端与服务器端如何进行文件传送的。
     在这之前,先来回顾一下上一篇‘Java Socket 01- 常识篇之消息处理’所讲到的内容: 1) 发送消息前如何对消息进行处理 2) 对消息如何进行编码 3)接收消息时如何对消息进行处理 4)发送端与接收端如何进行“对话”式的交互。其中讲到两个重要的概念:① 显式长度(Explicit length)  ②基于定界符(Delimiter-based)。
    文件的传送包括了两部分:文件的发送与文件的接收。文件发送端、文件的接收端这里分别简称为发送端、接收端。文件的传送也需要发送端与接收端协议好如何传送,比如,文件名,文件内容如何发送,谁先谁后,怎么编码等等。
    这里用简单的方法来完成文件的传送:首先发送文件名的长度,然后使用文件名,再发送文件内容的长度,最后发送文件的内容。这里先所以下规则,文件名的长度占4个字节,文件内容的长度占8个字节。如下图:

 附件会带上一个完整的源码:(下图是效果图)



 

下面来一段主要的源码(发送端):

	public void uploadFile(String sPath) throws IOException {
		long lStart = System.currentTimeMillis();
		// check the precondition
		FileInputStream oFileInput = new FileInputStream(new File(sPath));
		FileChannel oChannel = oFileInput.getChannel();
		// the File length
		long lLen = oChannel.size();
		// the file name
		String sFileName = sPath.substring(sPath.lastIndexOf(File.separator) + 1);
		byte[] bFileName = sFileName.getBytes("utf-8");
		// 发送文件名的长度和文件名到接收端
		m_handler.out().write(BasicTypeConverter.intToByte(bFileName.length));
		m_handler.out().write(bFileName);
		m_handler.out().flush();
		// 发送文件内容的长度和文件内容到接收端
		m_handler.out().write(BasicTypeConverter.longToByte(lLen));
		m_handler.out().flush();
		ByteBuffer oBuffer = ByteBuffer.allocate(1024);
		while (oChannel.read(oBuffer) != -1) {
			oBuffer.flip();
			if (oBuffer.hasRemaining()) {
				m_handler.out().write(oBuffer.array(), 0, oBuffer.limit());
				m_handler.out().flush();
			}
			oBuffer.clear();
		}
		oFileInput.close();
		oChannel.close();
		long lEnd = System.currentTimeMillis();
		long lUseTime =  lEnd - lStart;
		ClientFrame.self.setMsg("文件已经发送完成 ;文件大小:" + lLen/1024 + "KB; 共耗时:"+ lUseTime + "ms ----> "+ sPath);
	}

    如果对FileChannel 和ByteBuffer不了解,请看一下之前我写的博文,Java NIO里面有提到。这里给个链接http://jimmyhr.iteye.com/admin/categories/272010

     下面是一段主要的源码(接收端):

	@Override
	public void run() {
		try {
			// 文件名的长度
			byte[] bHeadLength = new byte[4];
			if (m_oIn.read(bHeadLength) == -1) {
				return;
			}
			// 获得文件名的长度
			int iLen = BasicTypeConverter.bytesToInt(bHeadLength);
			// 获得文件名
			ByteBuffer oBuffer = ByteBuffer.allocate(iLen);
			int iR = 0;
			while (oBuffer.hasRemaining()) {
				byte[] b = new byte[iLen - iR];
				iR += m_oIn.read(b);
				oBuffer.put(b);
			}
			String sFileName = new String(oBuffer.array(), "UTF-8");
			// 文件的长度
			bHeadLength = new byte[8];
			m_oIn.read(bHeadLength);
			long lFileLen = BasicTypeConverter.byteToLong(bHeadLength);
			// 接收文件并保存
			long lHasRev = 0;
			File oFile = new File(SAVEPATH + sFileName);
			if (!oFile.exists()) {
				File oDir = oFile.getParentFile();
				if (!oDir.exists()) {
					oDir.mkdirs();
				}
				oFile.createNewFile();
			}
			FileOutputStream oOut = new FileOutputStream(oFile);
			while (lHasRev < lFileLen) {
				int iAvail = m_oIn.available();
				byte[] b = new byte[Math.min((int) (lFileLen - lHasRev), iAvail)];
				int iRev = m_oIn.read(b);
				lHasRev += iRev;
				oOut.write(b, 0, iRev);
				oOut.flush();
			}
			oOut.close();
			ServerFrame.m_oFrame.setMsg("文件已经保存在:" + SAVEPATH + sFileName);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				m_oSocket.close();
				if (m_oIn != null) {
					m_oIn.close();
				}
				if (m_oOut != null) {
					m_oOut.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

  这里可能大家注意到 接收完成后,关闭Socket连接。所以例子中现在只支持单文件传送。大家不妨试试搞一下如何多文件传送。

  • 大小: 11.6 KB
  • 大小: 55.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics