關於windows主機之間傳輸文件,在不依賴於外部第三方服務的狀況下,大多會選擇 SMB/CIFS協議;關於 SMB/CIFS 協議相關的內容你們能夠自行查閱微軟官方文檔;java
目前本人測試本身的主機到 VMWare中的win7虛擬機傳輸文件,親測速率最快可達到 9MB/s(具體實際使用傳輸速度狀況,視硬件及網絡帶寬而定);spring
關鍵實現代碼以下所示:apache
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); } } } } }
能夠將文件傳輸封裝成異步任務,以便多線程上傳,以下所示:json
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; } }