SMB远程操作文件
- 远程->本地->远程
- 远程->远程
远程->本地->远程
- 下载远程文件,逐行修改符合条件的行内容,将修改完的文件重新上传到指定远程目录下
主要注意访问的url格式为:
smb://账号user:密码password@访问的ip/要访问的文件路径/文件.txt
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 根据文件路径找到共享文件,并修改参数值
*
* @author Chen
* @date 2022/4/1
*/
@Slf4j
public class UpdateShareFileDataUtil {
private static String TARGET_URL = "smb://***:***@***/share/java";
/**
* 获取远程文件,并根据参数值更新文本内容上传到指定路径
*
* @param filePath 本地格式存储的文件路径
* @param paramMap 需要更改的参数Map<参数名称,新参数值>
*/
@SuppressWarnings("unused")
public static void smbFile(String filePath, HashMap<String, String> paramMap) {
//初始化远程目录信息,将filePath格式转换成正确的 replace所有 \ 变成 /,去掉前两个字符
//根据自己项目需要进行转换
String remotePath = filePath.replace("\\", "/").substring(2);
//按smb格式拼接相关信息 smb://user:password@ip/testIndex/test.txt
String remoteUrl = "smb://user:password@" + remotePath;
String localDir = "E:\\tmp";
//判断本地是否有该目录,没有则创建
File file = new File(localDir);
if (!file.exists() && !file.isDirectory()) {
//如果要递归创建多层目录要用 mkdirs(),单层用 mkdir()也行
file.mkdirs();
}
//先下载到本地
smbGet(remoteUrl, localDir);
//更改内容,把filePath 文件名称前面无用的去除
String fileName = localDir + "\\" + filePath.substring(filePath.lastIndexOf("\\") + 1);
updateFile(fileName, paramMap);
}
/**
* 从共享目录下载文件到本地
*
* @param remoteUrl
* @param localDir
*/
private static void smbGet(String remoteUrl, String localDir) {
InputStream in = null;
OutputStream out = null;
try {
SmbFile remoteFile = new SmbFile(remoteUrl);
if (remoteFile == null) {
log.info("共享文件不存在");
return;
}
String fileName = remoteFile.getName();
File localFile = new File(localDir + File.separator + fileName);
in = new BufferedInputStream(new SmbFileInputStream(remoteFile));
out = new BufferedOutputStream(new FileOutputStream(localFile));
byte[] buffer = new byte[1024];
while (in.read(buffer) != -1) {
out.write(buffer);
buffer = new byte[1024];
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 修改本地文件内容,根据要求从values中匹配对应的参数进行重新赋值
* 这里是按每一行开头是否符合正则表达式进行修改,具体按个人需要
*
* @param localUrl
* @param paramMap
*/
private static void updateFile(String localUrl, HashMap<String, String> paramMap) {
//遍历行数的方法
try {
//定义正则表达式,只检查以 #数字= 开头的行数
String regex = "^#[0-9]=";
Pattern pattern = Pattern.compile(regex);
File file = new File(localUrl);
List<String> list = FileUtils.readLines(file,"UTF-8");
for (int i = 0; i < list.size(); i++){
//当前行内容值
String lineValue = list.get(i);
//判断当前行是否满足正则表达式的开头
Matcher marcher = pattern.matcher(lineValue);
if (marcher.find()){
//判断参数map中是否有对应的key,有就更新参数值,截取 = 号前的值
String param = lineValue.substring(0, lineValue.lastIndexOf("="));
if (paramMap.containsKey(param)) {
//如果有,则将param.value更换到 = 号后面 ; 前面的值
String newValue = param + "=" + paramMap.get(param) + ";";
//将重写后的当前行写回源文件
list.remove(i);
list.add(i,newValue);
}
}
}
FileUtils.writeLines(file, "UTF-8", list, false);
} catch (IOException e) {
log.info("更改参数值失败");
}
smbPut(TARGET_URL, localUrl);
}
/**
* 更新本地文件名
* @Param localUrl 文件路径
* @Param newName 新的文件名
*/
private static void updateFileName(String localUrl,String newName){
File file = new File(localUrl);
String fileName = file.getAbsolutePath();
fileName = fileName.substring(0,fileName.lastIndexOf(MdcsConstants.STR.BACK_SLASH)+1);
file.renameTo(new File(fileName + newName + ".nc"));
}
/*
* 检查远程文件是否存在
* 存在更改文件名
*
* @param smbUrl 远程文件url
* @param fileName 新的文件名
*/
private void checkFileExists(String smbUrl,String fileName){
try {
SmbFile smbFile = new SmbFile(smbUrl);
if (smbFile.exists() && smbFile.isFile()){
smbFile.renameTo(new SmbFile(smbUrl.substring(0,smbUrl.lastIndexOf(MdcsConstants.STR.SLASH)+1)+fileName+MdcsConstants.STR.UNDERSCORE+System.currentTimeMillis()+".nc"));
}
} catch (Exception e) {
log.info("文件修改名称失败");
}
}
/**
* 将本地文件上传至共享目录
*
* @param remoteUrl
* @param localFilePath
*/
private static void smbPut(String remoteUrl, String localFilePath) {
InputStream in = null;
OutputStream out = null;
try {
File localFile = new File(localFilePath);
String fileName = localFile.getName();
SmbFile remoteFile = new SmbFile(remoteUrl + "/" + fileName);
in = new BufferedInputStream(new FileInputStream(localFile));
out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
byte[] buffer = new byte[1024];
while (in.read(buffer) != -1) {
out.write(buffer);
buffer = new byte[1024];
}
} catch (Exception e) {
log.info("文件上传失败");
} finally {
try {
out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>(8);
map.put("#1","22222.");
map.put("#3","44444");
String filePath = "\\\\ip\\【Java从入门到入坟】.nc";
smbFile(filePath,map);
}
}
远程->远程
- 上面的代码是将共享文件下载到本地再进行修改操作,但是当项目发布时,这里的【本地】其实已经不一样了,不能再用类似本地主机时的操作,所以这里改成了直接将远程模板文件直接复制一份在远程临时目录下,直接修改,减少了一步从本地上传到远程的操作
- 这里有个地方不太一样,本地Windows环境下,读取文件内容时可以用
FileUtils.readLines(file,"UTF-8")
获取文件的每一行数据,但是当用 SMB 操作远程文件时,并没有提供相关api,所以改用文件流,具体看代码中的使用 - 此次修改抽取了大部分参数为外部传入
import com.jidian.mdcs.MdcsConstants;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import java.io.*;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 根据文件路径找到共享文件,并修改参数值
*
* @author ChenJunHao
* @date 2022/4/1 - 15:21
*/
@Slf4j
public class UpdateShareFileDataUtil {
/**
* @param filePath 本地格式存储的文件路径
* @param paramMap 需要更改的参数Map<参数名称,新参数值>
* @param targetUrl 上传路径
* @param punchCodeName 命名规则
* @param authMessage 拼接认证信息
* @param fileType 文件类型-后缀
* @param updateRegex 参数替换规则
*/
@SuppressWarnings("unused")
public static void smbFile(String filePath, Map<String, String> paramMap, String targetUrl, String punchCodeName,String authMessage,String fileType,String updateRegex) {
log.info("命中模板文件{}",filePath);
//装换
String remotePath = filePath.replace(MdcsConstants.STR.BACK_SLASH, MdcsConstants.STR.SLASH).substring(2);
//smb格式拼接 smb://user:password@ip/..
String remoteUrl = authMessage + remotePath;
SmbFile fileResult;
try {
fileResult = new SmbFile(targetUrl);
if (!fileResult.exists() && !fileResult.isDirectory()) {
fileResult.mkdirs();
}
} catch (Exception e) {
log.error("创建目标目录失败",e);
}
//下载
smbGet(remoteUrl, targetUrl);
//组装
String fileName = targetUrl + MdcsConstants.STR.SLASH + filePath.substring(filePath.lastIndexOf(MdcsConstants.STR.BACK_SLASH) + 1);
//文件更新
updateFile(fileName, paramMap,punchCodeName,fileType,updateRegex);
}
/**
* 将目标文件下载到目标目录
*
* @param remoteUrl
* @param localDir
*/
private static void smbGet(String remoteUrl, String localDir) {
log.info("开始下载远程模板文件{}",remoteUrl);
try {
SmbFile remoteFile = new SmbFile(remoteUrl);
if (ObjectUtils.isEmpty(remoteFile)) {
log.error("共享文件{}不存在",remoteUrl);
return;
}
String fileName = remoteFile.getName();
SmbFile localFile = new SmbFile(localDir + MdcsConstants.STR.SLASH + fileName);
//try-with-resources
try(InputStream in = new BufferedInputStream(new SmbFileInputStream(remoteFile));
OutputStream out = new BufferedOutputStream(new SmbFileOutputStream(localFile))
){
byte[] buffer = new byte[1024];
while (in.read(buffer) != -1) {
out.write(buffer);
buffer = new byte[1024];
}
}
} catch (Exception e) {
log.error("文件获取失败",e);
}
}
/**
* 修改本地文件内容,根据要求从values中匹配对应的参数进行重新赋值
*
* @param localUrl
* @param paramMap 包含了所命中的模板文件需要更新的参数及新值
* @param punchCodeName 新的文件名称
* @param fileType 文件类型-后缀
* @param updateRegex 文件参数替换规则
*
*/
private static void updateFile(String localUrl, Map<String, String> paramMap,String punchCodeName,String fileType,String updateRegex) {
log.info("更新模板文件{}",localUrl);
try {
Pattern pattern = Pattern.compile(updateRegex);
//判断l,b,d参数是否存在
String mpr = "mpr";
if (fileType.equals(mpr) ){
BufferedReader check = new BufferedReader(new InputStreamReader(new SmbFile(localUrl).getInputStream()));
updateCncMap(paramMap,check);
check.close();
}
List<String> list = new ArrayList<>();
String content = "";
StringBuilder stringBuilder = new StringBuilder(content);
//try-with-resources
try(BufferedReader br = new BufferedReader(new InputStreamReader(new SmbFile(localUrl).getInputStream(),"gbk"))){
String line;
//当前行是否有数据,可以有空行
//这里不用 !ObjectUtils.isEmpty(),因为这样会把空白行当成结束条件,这样如果文本内容中间有空白行就读取不到后面的内容了
while ((line = br.readLine()) != null) {
//判断当前行内容是否符合要求
Matcher marcher = pattern.matcher(line);
//正则匹配
if (marcher.find()){
//key值校验
String param = line.substring(0, line.lastIndexOf(MdcsConstants.STR.EQUALS));
if (paramMap.containsKey(param)) {
//更新参数值
String newValue = fileType.equals(mpr) ? param + MdcsConstants.STR.EQUALS + paramMap.get(param) :
param + MdcsConstants.STR.EQUALS + paramMap.get(param) + ";";
//记录新值
list.add(newValue);
}else {
list.add(line);
}
}else {
list.add(line);
}
}
}
//更新
list.stream().forEach(item-> stringBuilder.append(item).append("\n"));
OutputStream outputStream = new SmbFile(localUrl).getOutputStream();
outputStream.write(stringBuilder.toString().getBytes());
outputStream.close();
} catch (IOException e) {
log.error("更改参数值失败",e);
}
try {
updateFileName(localUrl,punchCodeName,fileType);
} catch (MalformedURLException e) {
log.error("url路径异常",e);
}
}
private static void updateFileName(String localUrl,String newName,String fileType) throws MalformedURLException {
log.info("开始更新文件 {} 名称为 {}",localUrl,newName);
SmbFile file = new SmbFile(localUrl);
String fileName = localUrl.substring(0,localUrl.lastIndexOf(MdcsConstants.STR.SLASH)+1);
try {
file.renameTo(new SmbFile(fileName + newName + MdcsConstants.STR.DOT+fileType));
} catch (SmbException e) {
log.error("更改文件名失败{}->{}",localUrl,newName,e);
}
}
/**
* 备份目录下旧数据
*
* @param backupUrl 存储目录
* @Param fileType 文件后缀类型
*/
public static void backupFile(String backupUrl, String fileType){
log.info("开始备份旧数据,目录{}",backupUrl);
String targetUrl = backupUrl + MdcsConstants.STR.SLASH;
//设置日期格式
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd_HHmmssSSS");
//未备份的文件集合
List<String> backupFileName = new ArrayList<>();
try {
SmbFile file = new SmbFile(targetUrl);
if (file.exists() && file.isDirectory()){
//获取该目录下的所有文件
SmbFile[] result = file.listFiles();
//筛选未备份文件
log.info("筛选未备份过的数据...");
for (int i=0; i<result.length; i++){
SmbFile fs = result[i];
if (!fs.getName().contains(MdcsConstants.STR.LEFT_SQ_BRACKET)){
backupFileName.add(fs.getName());
}
}
log.info("开始备份");
//对未备份的文件进行备份
for (String fileName:backupFileName){
// _[
String timeLeft = MdcsConstants.STR.UNDERSCORE + MdcsConstants.STR.LEFT_SQ_BRACKET;
// ].
String timeRight = MdcsConstants.STR.RIGHT_SQ_BRACKET + MdcsConstants.STR.DOT;
//备份后的名称
String backupName = targetUrl + fileName.substring(0,fileName.lastIndexOf(MdcsConstants.STR.DOT))
+timeLeft+df.format(new Date())+timeRight+fileType;
SmbFile smbFile = new SmbFile(targetUrl + fileName);
smbFile.renameTo(new SmbFile(backupName));
}
}
} catch (Exception e) {
log.error("文件目录不存在",e);
}
}
/**
* 判断是否有 l=,b=,d= 开头
* 没有就删除对应_BSX 等key
*/
private static Map<String,String> updateCncMap(Map<String,String> paramMap, BufferedReader br){
Map<String,Integer> lbdExists = new HashMap<>(8);
lbdExists.put("l",0);
lbdExists.put("b",0);
lbdExists.put("d",0);
//定义正则表达式,只检查以 l= b= d= 开头的行数
String regexL = "^(?=l=)";
String regexB = "^(?=b=)";
String regexD = "^(?=d=)";
Pattern patternL = Pattern.compile(regexL);
Pattern patternB = Pattern.compile(regexB);
Pattern patternD = Pattern.compile(regexD);
//遍历文件
try {
String line = "";
//是否满足条件
while ((line = br.readLine()) != null){
Matcher marcherL = patternL.matcher(line);
Matcher marcherB = patternB.matcher(line);
Matcher marcherD = patternD.matcher(line);
if (marcherL.find()){
lbdExists.put("l",1);
}else if (marcherB.find()){
lbdExists.put("b",1);
}else if (marcherD.find()){
lbdExists.put("d",1);
}
}
} catch (IOException e) {
log.error("获取文件内容失败",e);
}
//更新paramMap
String l = "l";
String b = "b";
String d = "d";
if (lbdExists.get(l) == 0){
//删除l参数及相关key
paramMap.remove("l");
paramMap.remove("_BSX");
paramMap.remove("_RX");
}else if (lbdExists.get(b) == 0){
//删除b参数相关key
paramMap.remove("b");
paramMap.remove("_BSY");
paramMap.remove("_RY");
}else if (lbdExists.get(d) == 0){
//删除d参数相关key
paramMap.remove("d");
paramMap.remove("_BSZ");
}
return paramMap;
}
private UpdateShareFileDataUtil(){}
}