文档章节

[CIFS/SMB]关于 windows 之间传输文件的Java代码实现

morpheusWB
 morpheusWB
发布于 01/13 02:10
字数 871
阅读 7
收藏 1

      关于windows主机之间传输文件,在不依赖于外部第三方服务的情况下,大多会选择 SMB/CIFS协议;关于 SMB/CIFS 协议相关的内容大家可以自行查阅微软官方文档;

      目前本人测试自己的主机到 VMWare中的win7虚拟机传输文件,亲测速率最快可达到 9MB/s(具体实际使用传输速度情况,视硬件及网络带宽而定);

关键实现代码如下所示:

package com.morpheus.transfer.win;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.Optional;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.morpheus.transfer.common.HostVO;
import com.morpheus.transfer.utils.CommonUtil;

import jcifs.UniAddress;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileOutputStream;
import jcifs.smb.SmbSession;

public class WinTransferService {
	private static final Logger LOGGER = LoggerFactory.getLogger(WinTransferService.class);
	public static final String KEY_JCIFS_SMB_CLIENT_DFS_DISABLED = "jcifs.smb.client.dfs.disabled";

	private HostVO hostVO = null;

	public WinTransferService(HostVO hostVO) {
		this.hostVO = hostVO;
	}

	private boolean validParams() {
		boolean notEmpty = CommonUtil.isAllNotEmpty(StringUtils.trimToEmpty(this.hostVO.getValidIP()),
				StringUtils.trimToEmpty(this.hostVO.getUserName()), StringUtils.trimToEmpty(this.hostVO.getUserPwd()));
		return notEmpty;
	}

	private boolean validParams(String... params) {
		boolean notEmpty = CommonUtil.isAllNotEmpty(StringUtils.trimToEmpty(this.hostVO.getValidIP()),
				StringUtils.trimToEmpty(this.hostVO.getUserName()), StringUtils.trimToEmpty(this.hostVO.getUserPwd()));
		boolean notEmptyParams = CommonUtil.isAllNotEmpty(params);
		return notEmpty && notEmptyParams;
	}

	public boolean loginToRemote() {
		if (!this.validParams()) {
			throw new IllegalArgumentException("Invalid host ip/userName/userPwd");
		}
		String domain = this.hostVO.getDomain();
		String userName = this.hostVO.getUserName();
		String userPwd = this.hostVO.getUserPwd();
		try {
			UniAddress uniDC = UniAddress.getByName(this.hostVO.getValidIP());
			NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(domain, userName, userPwd);
			SmbSession.logon(uniDC, auth);
			SmbFile smbFile = new SmbFile(String.format("cifs://%s/C$/", new Object[] { this.hostVO.getValidIP() }),
					auth);
			String[] files = smbFile.list();
			files = Optional.ofNullable(files).orElse(new String[0]);
			return files.length > 0;
		} catch (Throwable th) {
			LOGGER.error("WinTransferService.loginToRemote()	Throwable", th);
		}
		return false;
	}

	public InputStream readFromRemote(String remoteFile) throws IOException {
		if (!this.validParams(remoteFile)) {
			throw new IllegalArgumentException("Invalid host ip/userName/userPwd");
		}
		String domain = this.hostVO.getDomain();
		String userName = this.hostVO.getUserName();
		String userPwd = this.hostVO.getUserPwd();

		NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(domain, userName, userPwd);
		remoteFile = StringUtils.trimToEmpty(remoteFile);
		remoteFile = remoteFile.replace("\\", "/").replace(":", "$");
		SmbFile smbFile = new SmbFile(
				String.format("cifs://%s/%s", new Object[] { this.hostVO.getValidIP(), remoteFile }), auth);
		if (smbFile.exists()) {
			return smbFile.getInputStream();
		}
		return new ByteArrayInputStream("ReadFromRemoteError".getBytes());
	}

	public void createRemoteDir(String remoteDir, boolean deleteExist, NtlmPasswordAuthentication auth)
			throws MalformedURLException, SmbException {
		String remoteRelativePath = remoteDir.replace("\\", "/").replace(":", "$") + "/";
		String hostIP = this.hostVO.getValidIP();
		SmbFile smbDir = new SmbFile(String.format("cifs://%s/%s", new Object[] { hostIP, remoteRelativePath }), auth);
		if (deleteExist) {
			if (smbDir.exists()) {
				smbDir.delete();
			}
		}
		if (!smbDir.exists()) {
			smbDir.mkdirs();
		}
	}

	public void transferToRemote(String localPath, String remoteDir) throws IOException {
		if (!this.validParams(localPath, remoteDir)) {
			throw new IllegalArgumentException("Invalid host ip/userName/userPwd");
		}
		File localFile = new File(localPath);

		String domain = this.hostVO.getDomain();
		String userName = this.hostVO.getUserName();
		String userPwd = this.hostVO.getUserPwd();

		LOGGER.info("WinTransferService.transferToRemote()	begin: localPath={}, remoteDir={}", localPath, remoteDir);
		System.setProperty(KEY_JCIFS_SMB_CLIENT_DFS_DISABLED, String.valueOf(true));
		jcifs.Config.setProperty(KEY_JCIFS_SMB_CLIENT_DFS_DISABLED, String.valueOf(true));
		NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(domain, userName, userPwd);
		if (localFile.isFile()) {
			remoteDir = remoteDir.replace("\\", "/") + "/";
			this.createRemoteDir(remoteDir, false, auth);
			this.uploadFileWithSmb(localFile, remoteDir, auth);
		} else if (localFile.isDirectory()) {
			remoteDir = remoteDir.replace("\\", "/") + "/" + localFile.getName();
			this.createRemoteDir(remoteDir, true, auth);
			this.uploadDirWithSmb(localFile, remoteDir, auth);
		}
		LOGGER.info("WinTransferService.transferToRemote()	end: localPath={}, remoteDir={}", localPath, remoteDir);
	}

	public void uploadFileWithSmb(File localFile, String remoteDir, NtlmPasswordAuthentication auth) {
		FileInputStream fileInputStream = null;
		SmbFileOutputStream smbFileOutputStream = null;
		try {
			String remoteRelativePath = remoteDir.replace("\\", "/").replace(":", "$") + "/" + localFile.getName();
			SmbFile smbFile = new SmbFile(
					String.format("cifs://%s/%s", new Object[] { this.hostVO.getValidIP(), remoteRelativePath }), auth);
			smbFileOutputStream = new SmbFileOutputStream(smbFile);
			fileInputStream = new FileInputStream(localFile);
			IOUtils.copyLarge(fileInputStream, smbFileOutputStream);
		} catch (Throwable th) {
			LOGGER.error("TransferService.putFileWithSamba()	Throwable", th);
		} finally {
			IOUtils.closeQuietly(fileInputStream);
			IOUtils.closeQuietly(smbFileOutputStream);
		}
	}

	public void uploadDirWithSmb(File localDir, String remoteDir, NtlmPasswordAuthentication auth) throws IOException {
		File[] files = localDir.listFiles();
		files = Optional.ofNullable(files).orElse(new File[0]);
		for (File file : files) {
			if (file.isDirectory()) {
				String relativeDestFile = remoteDir.replace("\\", "/").replace(":", "$") + "/" + file.getName();
				SmbFile smbFile = new SmbFile(
						String.format("cifs://%s/%s", new Object[] { this.hostVO.getValidIP(), relativeDestFile }),
						auth);
				if (!smbFile.exists()) {
					smbFile.mkdirs();
				} else if (smbFile.isDirectory()) {
					smbFile.delete();
				}
				this.uploadDirWithSmb(file, remoteDir + "/" + file.getName(), auth);
			} else if (file.isFile()) {
				FileInputStream fileInputStream = null;
				SmbFileOutputStream smbFileOutputStream = null;
				try {
					String relativeDestFile = remoteDir.replace("\\", "/").replace(":", "$") + "/" + file.getName();
					SmbFile smbFile = new SmbFile(
							String.format("cifs://%s/%s", new Object[] { this.hostVO.getValidIP(), relativeDestFile }),
							auth);
					smbFileOutputStream = new SmbFileOutputStream(smbFile);
					fileInputStream = new FileInputStream(file);
					IOUtils.copyLarge(fileInputStream, smbFileOutputStream);
				} finally {
					IOUtils.closeQuietly(fileInputStream);
					IOUtils.closeQuietly(smbFileOutputStream);
				}
			}
		}
	}
}

可以将文件传输封装成异步任务,以便多线程上传,如下所示:

package com.morpheus.transfer.win;

import java.util.concurrent.Callable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import com.alibaba.fastjson.JSONObject;
import com.morpheus.transfer.common.HostVO;
import com.morpheus.transfer.utils.JSONUtil;

public class TransferJob implements Callable<JSONObject> {
	private static final Logger LOGGER = LoggerFactory.getLogger(TransferJob.class);

	private WinTransferService winTransferService = null;

	private String localDir = null;
	private String remoteDir = null;

	public TransferJob(HostVO hostVO, String localDir, String remoteDir) {
		this.winTransferService = new WinTransferService(hostVO);
		this.localDir = localDir;
		this.remoteDir = remoteDir;
	}

	@Override
	public JSONObject call() throws Exception {
		JSONObject resJSON = new JSONObject();
		try {
			boolean login = this.winTransferService.loginToRemote();
			if (login) {
				this.winTransferService.transferToRemote(this.localDir, this.remoteDir);
				resJSON = JSONUtil.createResult(resJSON, true, HttpStatus.OK.value(), "TransferFinished");
			}
		} catch (Throwable th) {
			LOGGER.error("TransferJob.call()	Throwable", th);
			resJSON = JSONUtil.createResult(resJSON, true, HttpStatus.OK.value(), "TransferError");
		}
		return resJSON;
	}
}

 

© 著作权归作者所有

共有 人打赏支持
morpheusWB
粉丝 22
博文 83
码字总数 13647
作品 0
西安
程序员
私信 提问
SMB介绍及Linux下搭建Samba服务器

文件同步 镜像, 增量备份 rsync, UNIX系统下的数据镜像备份工具; Samba 是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。 SMB (Server Messages Block) 一种在局...

老张他爹945
2017/10/27
0
0
JFtp 1.56 发布,Java开发的FTP客户端

一个用JAVA写的FTP客户端程序。功能强大不仅支持FTP,还支持其它协议如SMB, SFTP, NFS, HTTP等。在传输文件的同时还可以浏览FTP服务器上的资源,也可以浏览局域网上的Windows共享资源等 JFtp...

oschina
2012/05/31
924
5
StelsDBF 4.2 发布

StelsDBF 是一个 DBF 数据库文件的 JDBC Type 4 的驱动程序,例如 dBase III/IV/V, xBase, and FoxPro。 新版本增加对 SMB/CIFS and CLASSPATH URLs 的支持。...

红薯
2010/10/07
240
0
linux命令(一):Linux Crontab 定时任务

cron介绍 cron英文意思:计划任务,我们经常使用的是crontab命令是cron table的简写,它是cron的配置文件,也可以叫它作业列表,我们可以在以下文件夹内找到相关配置文件。 /var/spool/cron/...

AHUSKY
2018/06/29
0
0
通过Alfresco DM 架设网络文件服务-CIFS及WebDAV

Alfresco DM为网络文件服务提供了一个虚拟的文件系统(是纯Java的),并支持CIFS及WebDAV网络文件访问协议。当你需要在企业局域网及互联网上同时架设一个可以供企业员工使用的安全而可靠的文...

YipChooli
2010/04/18
2.3K
0

没有更多内容

加载失败,请刷新页面

加载更多

MySQL查询执行

当我们希望MySQL能够以更高的性能运行查询时,最好的办法就是弄清楚MySQL是如何优化和执行查询的。一旦理解了这一点,很多查询优化工作实际上就是遵循一些原则让优化器能够按照预想的合理方式...

Linux就该这么学
8分钟前
0
0
爱可生开源社区官网正式发布啦!

近期大事记 2018/12/31 DBLE年度报告发版 2019/01/07 DBLE 2.18.12.0 新版发布,修复 issue 60+ 2019/01/09 DBLE 2.18.12.0 Release Notes 详细解读 2019/01/15 DBLE Logo 首发 + DBLE 团队迎......

爱可生
15分钟前
0
0
【分布式缓存系列】Redis实现分布式锁的正确姿势

一、前言   在我们日常工作中,除了Spring和Mybatis外,用到最多无外乎分布式缓存框架——Redis。但是很多工作很多年的朋友对Redis还处于一个最基础的使用和认识。所以我就像把自己对分布式...

编辑之路
26分钟前
0
0
3.x 在Unix系统上面启动守护进程

12.14 在Unix系统上面启动守护进程 问题 你想编写一个作为一个在Unix或类Unix系统上面运行的守护进程运行的程序。 解决方案 创建一个正确的守护进程需要一个精确的系统调用序列以及对于细节的...

dragon_tech
27分钟前
0
0
ES6中的class

class Point {constructor(x, y, z) {this.x = x;this.y = y;this.z = z;}toString() {return `${this.x},${this.y}`}get prop() {return `获取的是get${this.z...

chinahufei
29分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部