- SMB
SMB(Server Message Block)通信协议是微软(Microsoft)和英特尔(Intel)在1987年制定的协议,主要是作为Microsoft网络的通讯协议。SMB 是在会话层(session layer)和表示层(presentation layer)以及小部分应用层(application layer)的协议。
-
本章代码是通过配置文件把服务器IP、用户名、‘密码、下载后本地路径等信息转为可配置的XML文件,方便多服务器应用,也可把IP、用户名等信息固定在程序中
-
所需jar
<!-- smb 共享文件 -->
<dependency>
<groupId>org.samba.jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.3</version>
</dependency>
<!-- Dom4j解析XML -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
- Xml文件
<?xml version="1.0" encoding="UTF-8"?>
<type>
<smbs>
<smb id="1" ip="192.168.6.121" username="user1" password="voicecyber@123" path="/tomcat/" localPath="F:/vcc/" />
</smbs>
</type>
- XML配置文件所在目录
public class SystemConfig {
public static class FileLocation{
public static String baseLocation="c:/voicecyber/";
}
}
- 读取XML文件的工具类(此工具类可用于大多数XML解析)
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.*;
import java.util.*;
/**
* @Author: YafengLiang
* @Description:
* @Date: Created in 11:39 2018/11/30
*/
public class XmlUtils {
/**
* @Description: 根据xml文件路径取得document对象
*/
public static Document getDocument(String xmlPath) {
if (xmlPath == null || (xmlPath.trim()).equals("")) {
return null;
}
SAXReader reader = new SAXReader();
Document document = null;
try {
document = reader.read(new File(xmlPath));
} catch (DocumentException e) {
e.printStackTrace();
}
return document;
}
/**
* @Description: 根据document对象获取到根节点
*/
public static Element getRootNode(Document document) {
if (document == null) {
return null;
}
Element root = document.getRootElement();
return root;
}
/**
* @Description: 根据路径直接拿到根节点
*/
public static Element getRootNode(String xmlPath) {
if (xmlPath == null || (xmlPath.trim()).equals("")) {
return null;
}
Document document = getDocument(xmlPath);
if (document == null) {
return null;
}
return getRootNode(document);
}
/**
* @Description: 得到指定元素的迭代器
*/
public static Iterator<Element> getIterator(Element parent) {
if (parent == null) {
return null;
}
Iterator<Element> iterator = parent.elementIterator();
return iterator;
}
/**
* @Description: 根据子节点名称得到指定的子节点
*/
public static List<Element> getChildElements(Element parent, String childName) {
childName = childName.trim();
if (parent == null) {
return null;
}
childName = "//" + childName;
List<Element> childElements = parent.selectNodes(childName);
return childElements;
}
/**
* @Description: getChildList
*/
public static List<Element> getChildList(Element node) {
if (node == null) {
return null;
}
Iterator<Element> iterator = getIterator(node);
if (iterator == null) {
return null;
}
List<Element> childList = new ArrayList<Element>();
while (iterator.hasNext()) {
Element kidElement = iterator.next();
if (kidElement != null) {
childList.add(kidElement);
}
}
return childList;
}
/**
* @Description: 查询没有子节点的节点,使用xpath方式
*/
public static Node getSingleNode(Element parent, String nodeName) {
nodeName = nodeName.trim();
String xpath = "//";
if (parent == null) {
return null;
}
if (nodeName == null || nodeName.equals("")) {
return null;
}
xpath += nodeName;
Node kid = parent.selectSingleNode(xpath);
return kid;
}
/**
* @Description: 判断节点是否还有子节点
*/
public static boolean hasChild(Element element) {
if (element == null) {
return false;
}
return element.hasContent();
}
/**
* @Description: 得到指定节点的属性的迭代器
*/
public static Iterator<Attribute> getAttrIterator(Element element) {
if (element == null) {
return null;
}
Iterator<Attribute> attrIterator = element.attributeIterator();
return attrIterator;
}
/**
* @Description: 遍历指定节点的所有属性
*/
public static List<Attribute> getAttributeList(Element element) {
if (element == null) {
return null;
}
List<Attribute> attributeList = new ArrayList<Attribute>();
Iterator<Attribute> attrIterator = getAttrIterator(element);
if (attrIterator == null) {
return null;
}
while (attrIterator.hasNext()) {
Attribute attribute = attrIterator.next();
attributeList.add(attribute);
}
return attributeList;
}
/**
* @Description: 得到指定节点的指定属性
*/
public static Attribute getAttribute(Element element, String attrName) {
attrName = attrName.trim();
if (element == null) {
return null;
}
if (attrName == null || attrName.equals("")) {
return null;
}
Attribute attribute = element.attribute(attrName);
return attribute;
}
/**
* @Description: 获取指定节点指定属性的值
*/
public static String attrValue(Element element, String attrName) {
attrName = attrName.trim();
if (element == null) {
return null;
}
if (attrName == null || attrName.equals("")) {
return null;
}
return element.attributeValue(attrName);
}
/**
* @Description: 得到指定节点所有属性及属性值
*/
public static Map<String, String> getNodeAttrMap(Element element) {
Map<String, String> attrMap = new HashMap<String, String>();
if (element == null) {
return null;
}
List<Attribute> attributes = getAttributeList(element);
if (attributes == null) {
return null;
}
for (Attribute attribute : attributes) {
String attrValueString = attrValue(element, attribute.getName());
attrMap.put(attribute.getName(), attrValueString);
}
return attrMap;
}
/**
* @Description: 根据节点名称获取text值
*/
public static String textValue(Element element, String elementName) {
if (elementName == null || (elementName.trim()).equals("")) {
return null;
}
return element.getTextTrim();
}
/**
* @Description: 节点text转换成int
*/
public static Integer TextValueToInt(String textValue) {
if (textValue == null || (textValue.trim()).equals("")) {
return null;
}
return Integer.parseInt(textValue.trim());
}
/**
* @Description: 遍历指定节点下没有子节点的元素的text值
*/
public static Map<String, String> getStringNodeText(Element element) {
Map<String, String> map = new HashMap<String, String>();
if (element == null) {
return null;
}
List<Element> kids = getChildList(element);
for (Element element2 : kids) {
if (element2.getTextTrim() != null) {
map.put(element2.getName(), element2.getTextTrim());
}
}
return map;
}
/**
* @Description: 删除指定节点
*/
public static boolean removeElemet(Element parent, String nodeName) {
boolean flag = false;
nodeName = nodeName.trim();
String xpath = "";
if (parent == null) {
return flag;
}
if (nodeName == null || nodeName.equals("")) {
return flag;
}
xpath += nodeName;
List<Element> elementList = getChildElements(parent, xpath);
if (elementList == null || elementList.size() <= 0) {
return flag;
}
for (Element element : elementList) {
element.getParent().remove(element);
flag = true;
}
return flag;
}
/**
* @Description: 修改节点属性值
*/
public static void updateAttrValue(Element element, String attrName, String attrVal) {
if (element != null && attrName.trim() != null && attrName.trim() != "") {
Attribute attribute = element.attribute(attrName);
if (attribute != null) {
attribute.setValue(attrVal);
}
}
}
/**
* @Description: 修改xml, 按路径保存
*/
public static void saveXml(String xmlPath, Document document) {
FileOutputStream out = null;
try {
out = new FileOutputStream(xmlPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
format.setExpandEmptyElements(true);
XMLWriter writer = null;
try {
writer = new XMLWriter(out, format);
writer.write(document);
writer.close();
out.close();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 工具类ApplicationConstants(XML文件名称)
/**
* @Author: YafengLiang
* @Description:
* @Date: Created in 11:44 2018/11/30
*/
public interface ApplicationConstants {
interface FileName {
String THAILAND_SUBWAY = "ThailandSubway.xml";
}
}
- 主要代码部分
import com.utils.ApplicationConstants;
import com.utils.SystemConfig;
import com.utils.XmlUtils;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.List;
/**
* @Author: YafengLiang
* @Description:
* @Date: Created in 11:48 2018/12/7
*/
public class SmbTest {
private static final Logger logger = LoggerFactory.getLogger(SmbTest.class);
public static void main(String[] args) {
MyRun myRun = new MyRun();
new Thread(myRun).start();
}
/**
* 实时同步共享目录文件到本地
*/
public static class MyRun implements Runnable {
@Override
public void run() {
String rootFile = SystemConfig.FileLocation.baseLocation+ ApplicationConstants.FileName.THAILAND_SUBWAY;
Element rootElement = XmlUtils.getRootNode(rootFile);
List<Element> list = XmlUtils.getChildElements(rootElement,"smb");
String id1 = "1";
if (list.size()>0){
for (Element element : list) {
String ids = element.attributeValue("id");
if (id1.equals(ids)){
String HOST = element.attributeValue("ip");
String USERNAME = element.attributeValue("username");
String PASSWORD = element.attributeValue("password");
String PATH = element.attributeValue("path");
String LOCAL_DIRECTORY = element.attributeValue("localPath");
String URL = "smb://"+HOST+PATH;
while (true) {
try {
logger.info("十秒后开始。。。。。。");
Thread.sleep(10 * 1000);
logger.info("继续。。。。。。");
getRemoteFile(URL,USERNAME,PASSWORD,LOCAL_DIRECTORY,HOST);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
/**
* 获取远程文件
* @param remoteUsername 远程目录访问用户名
* @param remotePassword 远程目录访问密码
* @param url 远程文件地址,该参数需以IP打头,如'192.168.6.121/aa/bb.java'或者'192.168.6.121/aa/',如'192.168.6.121/aa'是不对的
* @param localDirectory 本地存储目录,该参数需以'/'结尾,如'D:/'或者'D:/mylocal/'
* @return boolean 是否获取成功
* @throws Exception
*/
public static boolean getRemoteFile(String url,String remoteUsername, String remotePassword,
String localDirectory,String HOST) throws Exception {
boolean isSuccess = Boolean.FALSE;
if (url.startsWith("/") || url.startsWith("\\")) {
return isSuccess;
}
if (!(localDirectory.endsWith("/") || localDirectory.endsWith("\\"))) {
return isSuccess;
}
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(HOST,remoteUsername,remotePassword);
SmbFile smbFile = new SmbFile(url, auth);
if (smbFile != null) {
if (smbFile.isDirectory()) {
SmbFile[] smbFiles = smbFile.listFiles();
for (SmbFile file : smbFiles) {
File file1 = new File(localDirectory+File.separator+file.getName());
if (smbFile.isDirectory()) {
getRemoteFile(url + File.separator + file.getName(), remoteUsername, remotePassword, localDirectory + File.separator + file.getName(),HOST);
if (!file1.exists()) {
isSuccess = copyFile(file, localDirectory);
}else {
logger.info("已存在 "+file1);
String smbUrl = url + File.separator + file.getName();
String str = smbUrl.replace("\\\\","");
SmbFile smbFile1 = new SmbFile(str,auth);
smbFile1.delete();
logger.info("删除:"+smbUrl.replace("\\\\","")+" 成功");
}
}else {
isSuccess = copyFile(file, localDirectory);
}
}
} else if (smbFile.isFile()) {
isSuccess = copyFile(smbFile, localDirectory);
}
}
return isSuccess;
}
/**
* 拷贝远程文件到本地目录
* @param smbFile 远程SmbFile
* @param localDirectory 本地存储目录,本地目录不存在时会自动创建,本地目录存在时可自行选择是否清空该目录下的文件,默认为不清空
* @return boolean 是否拷贝成功
*/
public static boolean copyFile(SmbFile smbFile, String localDirectory) {
SmbFileInputStream in = null;
FileOutputStream out = null;
try {
File[] localFiles = new File(localDirectory).listFiles();
if (null == localFiles) {
// 目录不存在的话,就创建目录
new File(localDirectory).mkdirs();
logger.info(localDirectory+"目录创建成功!");
}
in = new SmbFileInputStream(smbFile);
out = new FileOutputStream(localDirectory + smbFile.getName());
byte[] buffer = new byte[4096];
int len = -1;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
buffer = new byte[4096];
}
out.flush();
logger.info("拷贝 "+smbFile.getName()+" 成功");
} catch (Exception e) {
logger.error("拷贝远程文件到本地目录失败", e);
return false;
} finally {
if (null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
}