java-FTPClient-ftp 上传文件、创建目录(支持中文目录、文件名)

java-ftp 上传、删除文件(支持中文目录、文件名)


一、问题
描述:Java中FTPClient上传中文目录、中文文件名乱码问题解决方法
原因:FTP协议里面,规定文件名编码为iso-8859-1,所以目录名或文件名需要转码。
解决方案:name=new String(name.getBytes("GBK"),"iso-8859-1"); 使用这个转码


二、ftp 文件上传帮助类
package me.grass.net;


import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.function.Function;


import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;


import me.grass.coder.Debug;
import me.grass.extend.PathExtend;
import me.grass.extend.StringExtend;


/**
 *
 * @author xxj
 */
public class FtpHelper implements Closeable {
	private FTPClient ftp = null;
	boolean _isLogin = false;
	public static FtpHelper getInstance() {
		return new FtpHelper();
	}
	
	/**
	 * 
	 * ftp 匿名登录
	 * @param ip ftp服务地址
	 * @param port 端口号
	 * @param uname 用户名
	 * @param pass 密码
	 */
	public boolean login(String ip,int port){
		//如果没有设置ftp用户可将username设为anonymous,密码为任意字符串
		return login(ip, port,"anonymous","");
	} 
	/**
	 * 
	 * ftp登录
	 * @param ip ftp服务地址
	 * @param port 端口号
	 * @param uname 用户名
	 * @param pass 密码
	 * @param workingDir ftp 根目目录
	 */
	public boolean login(String ip,int port, String uname, String pass) {
		ftp = new FTPClient();
//		boolean flag=false;
		try {
			// 连接
			ftp.connect(ip,port);
			_isLogin = ftp.login(uname, pass);
			Debug.printFormat("ftp:{0}",_isLogin?"登录成功":"登录失败");
			// 检测连接是否成功
			int reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				System.err.println("FTP服务器拒绝连接 ");
				return false;
			}
			return true;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		}
	}
	/**
	 * 上传后触发
	 */
	public Function onUploadFileAfter;
	
	/**
	 * 
	 * ftp上传文件 
	 * @param localFileName 待上传文件
	 * @param ftpDirName ftp 目录名
	 * @param ftpFileName ftp目标文件
	 * @return true||false
	 */
	public boolean uploadFile(String localFileName
			,String ftpDirName
			, String ftpFileName) {
		return uploadFile(localFileName, ftpDirName, ftpFileName,false);
	}
	/**
	 * 
	 * ftp上传文件 
	 * @param localFileName 待上传文件
	 * @param ftpDirName ftp 目录名
	 * @param ftpFileName ftp目标文件
	 * @param deleteLocalFile 是否删除本地文件
	 * @return true||false
	 */
	public boolean uploadFile(String localFileName
			, String ftpDirName
			, String ftpFileName
			, boolean deleteLocalFile) {


		Debug.printFormat("准备上传 [{0}] 到 ftp://{1}/{2}"
				,localFileName
				,ftpDirName
				,ftpFileName);
//		if(StringExtend.isNullOrEmpty(ftpDirName))
//			ftpDirName="/";
		if(StringExtend.isNullOrEmpty(ftpFileName))
			throw new RuntimeException("上传文件必须填写文件名!");
		
		File srcFile = new File(localFileName);
		if(!srcFile.exists())
			throw new RuntimeException("文件不存在:"+localFileName);
		
		try (FileInputStream fis = new FileInputStream(srcFile)) {
			//上传文件
			boolean flag = uploadFile(fis,ftpDirName,ftpFileName);
			//上传前事件
			if(onUploadFileAfter!=null){
				onUploadFileAfter.apply(new FtpFileInfo(localFileName,ftpDirName,ftpFileName));
			}
			//删除文件
			if(deleteLocalFile){
				srcFile.delete();
				Debug.printFormat("ftp删除源文件:{0}",srcFile);
			}
			fis.close();
			return flag;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
		}
	}


	/**
	 * 
	 * ftp上传文件 (使用inputstream)
	 * @param localFileName 待上传文件
	 * @param ftpDirName ftp 目录名
	 * @param ftpFileName ftp目标文件
	 * @return true||false
	 */
	public boolean uploadFile(FileInputStream uploadInputStream
			,String ftpDirName
			, String ftpFileName) {
		Debug.printFormat("准备上传 [流] 到 ftp://{0}/{1}"				
				,ftpDirName
				,ftpFileName);
//		if(StringExtend.isNullOrEmpty(ftpDirName))
//			ftpDirName="/";
		if(StringExtend.isNullOrEmpty(ftpFileName))
			throw new RuntimeException("上传文件必须填写文件名!");
		
		try {
			// 设置上传目录(没有则创建)
			if(!createDir(ftpDirName)){
				throw new RuntimeException("切入FTP目录失败:"+ftpDirName);
			}
			ftp.setBufferSize(1024);
			//解决上传中文 txt 文件乱码
			ftp.setControlEncoding("GBK");
			FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT); 
			conf.setServerLanguageCode("zh");  


			// 设置文件类型(二进制)
			ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
			// 上传
			String fileName = new String(ftpFileName.getBytes("GBK"),"iso-8859-1");
			if(ftp.storeFile(fileName, uploadInputStream)){
				uploadInputStream.close();
				Debug.printFormat("文件上传成功:{0}/{1}"
						,ftpDirName
						,ftpFileName);
				return true;
			}
			
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
		}
	}
	/**
	 * 下载文件
	 * @param ftpDirName ftp目录名
	 * @param ftpFileName ftp文件名
	 * @param localFileFullName 本地文件名
	 * @return
	 *  @author xxj
	 */
	public boolean downloadFile(String ftpDirName,
			String ftpFileName, String localFileFullName) {
		try {
			if("".equals(ftpDirName))
				ftpDirName="/";
			String dir = new String(ftpDirName.getBytes("GBK"),"iso-8859-1");
			if(!ftp.changeWorkingDirectory(dir)){
				System.out.println("切换目录失败:"+ftpDirName);
				return false;
			}
			FTPFile[] fs = ftp.listFiles();
			String fileName = new String(ftpFileName.getBytes("GBK"),"iso-8859-1");
			for (FTPFile ff : fs) {
				if (ff.getName().equals(fileName)) {
					FileOutputStream is = new FileOutputStream(new File(localFileFullName));
					ftp.retrieveFile(ff.getName(), is);
					is.close();
					System.out.println("下载ftp文件已下载:"+localFileFullName);
					return true;
				}
			}
			System.out.println("下载ftp文件失败:"+ftpFileName+";目录:"+ftpDirName);
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} 
	}


	/**
	 * 
	 * 删除ftp上的文件
	 * 
	 * @param ftpFileName
	 * @return true || false
	 */
	public boolean removeFile(String ftpFileName) {
		boolean flag = false;
		Debug.printFormat("待删除文件:{0}"
				,ftpFileName);
		try {
			ftpFileName = new String(ftpFileName.getBytes("GBK"),"iso-8859-1");
			flag = ftp.deleteFile(ftpFileName);
			Debug.printFormat("删除文件:[{0}]"
					,flag?"成功":"失败");
			return flag;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 删除空目录
	 * @param dir
	 * @return
	 */
	public boolean removeDir(String dir){
		if(StringExtend.startWith(dir, "/"))
			dir="/"+dir;
		try {
			String d = new String(dir.toString().getBytes("GBK"),"iso-8859-1");			
			return ftp.removeDirectory(d);			
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 创建目录(有则切换目录,没有则创建目录)
	 * @param dir
	 * @return
	 */
	public boolean createDir(String dir){
		if(StringExtend.isNullOrEmpty(dir))
			return true;
		String d;
		try {
			//目录编码,解决中文路径问题
			d = new String(dir.toString().getBytes("GBK"),"iso-8859-1");
			//尝试切入目录
			if(ftp.changeWorkingDirectory(d))
				return true;
			dir = StringExtend.trimStart(dir, "/");
			dir = StringExtend.trimEnd(dir, "/");
			String[] arr =  dir.split("/");
			StringBuffer sbfDir=new StringBuffer();
			//循环生成子目录
			for(String s : arr){
				sbfDir.append("/");
				sbfDir.append(s);
				//目录编码,解决中文路径问题
				d = new String(sbfDir.toString().getBytes("GBK"),"iso-8859-1");
				//尝试切入目录
				if(ftp.changeWorkingDirectory(d))
					continue;
				if(!ftp.makeDirectory(d)){
					System.out.println("[失败]ftp创建目录:"+sbfDir.toString());
					return false;
				}
				System.out.println("[成功]创建ftp目录:"+sbfDir.toString());
			}
			//将目录切换至指定路径
			return ftp.changeWorkingDirectory(d);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	


	/**
	 *
	 * 销毁ftp连接
	 *
	 */
	private void closeFtpConnection() {
		_isLogin = false;
		if (ftp != null) {
			if (ftp.isConnected()) {
				try {
					ftp.logout();
					ftp.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}


	/**
	 *
	 * 销毁ftp连接
	 *
	 */
	@Override
	public void close() {
		this.closeFtpConnection();
	}
	
	public static class FtpFileInfo{
		public FtpFileInfo(String srcFile,String ftpDirName,String ftpFileName){
			this.ftpDirName=ftpDirName;
			this.ftpFileName=ftpFileName;
			this.srcFile=srcFile;
		}
		String srcFile;
		String ftpDirName;
		String ftpFileName;
		String ftpFileFullName;
		
		public String getSrcFile() {
			return srcFile;
		}
		public void setSrcFile(String srcFile) {
			this.srcFile = srcFile;
		}
		public String getFtpDirName() {
			return ftpDirName;
		}
		public void setFtpDirName(String ftpDirName) {
			this.ftpDirName = ftpDirName;
		}
		public String getFtpFileName() {
			return ftpFileName;
		}
		public void setFtpFileName(String ftpFileName) {
			this.ftpFileName = ftpFileName;
		}
		/**
		 * 获取ftp上传文件的完整路径名
		 * @return
		 *  @author xxj
		 */
		public String getFtpFileFullName() {
			return PathExtend.Combine("/",ftpDirName,ftpFileName);
		}
		
	}
}




三、ftp 上传单元测试

package me.grass.net;




import static org.junit.Assert.*;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;


import javax.print.attribute.standard.Finishings;


import org.apache.taglibs.standard.lang.jstl.test.beans.PublicInterface2;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


import me.grass.extend.DateExtend;
import me.grass.extend.StringExtend;
import me.grass.net.FtpHelper;


/** 
*
* @author xxj 
*/
public class FtpHelperTest {
	FtpHelper ftp=null;
	@Before
	public void InitBinder(){
		ftp = FtpHelper.getInstance();
		ftp.login("localhost", 21);//匿名登录
	}
	@After
	public void finish(){
		ftp.close();
	}
	@Test
	public void testUplodFileStream() {
		
		try {			
			String localFile="D:/Temp/resource/img.jpg";
			String ftpDir="temp";
			String ftpFile=StringExtend.format("img-{0}.jpg"
					, DateExtend.getDate("yyyyMMddHHmmss"));


			
			FileInputStream fi = new FileInputStream(localFile);
			
			boolean success = ftp.uploadFile(fi,ftpDir, ftpFile);
			assertTrue(success);


			localFile="D:/Temp/resource/文本.txt";
			ftpDir="temp";
			ftpFile=StringExtend.format("文本-{0}.txt"
					, DateExtend.getDate("yyyyMMddHHmmss"));	


			fi = new FileInputStream(localFile);
			success = ftp.uploadFile(fi,ftpDir, ftpFile);	
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}			
	}
	@Test
	public void testOnAfter() {
		String localFile="D:/Temp/resource/img.jpg";
		String ftpDir="/aa/bb";
		String ftpFile=StringExtend.format("img-{0}.jpg"
				, DateExtend.getDate("yyyyMMddHHmmss"));	


		// 上传后事件
		ftp.onUploadFileAfter = (ftpFileInfo) -> {
			try(FileInputStream fstream = new FileInputStream(new File(ftpFileInfo.getSrcFile()))) {
				ByteArrayOutputStream bstream = new ByteArrayOutputStream();
				byte[] buffer = new byte[1000];
				int n = 0;
				while ((n = fstream.read(buffer)) != -1) {
					bstream.write(buffer, 0, n);
				}
				System.out.println("onafter:stream lenth = "+bstream.size());
				bstream.close();
				fstream.close();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}


			return true;
		};
		//上传
		boolean success = ftp.uploadFile(localFile,ftpDir, ftpFile);
		assertTrue(success);
		
	}
	@Test
	public void testUplodaFile() {
		String localFile="D:/Temp/resource/img.jpg";
		String ftpDir="/aa/bb";
		String ftpFile=StringExtend.format("img-{0}.jpg"
				, DateExtend.getDate("yyyyMMddHHmmss"));		
		boolean success = ftp.uploadFile(localFile,ftpDir, ftpFile);
		assertTrue(success);
		
		localFile="D:/Temp/resource/text.txt";
		ftpDir="/aa/bb/c1";
		ftpFile=StringExtend.format("text-{0}.txt"
				, DateExtend.getDate("yyyyMMddHHmmss"));		
		success = ftp.uploadFile(localFile,ftpDir, ftpFile);		
		assertTrue(success);


		localFile="D:/Temp/resource/文本.txt";
		ftpDir="/aa/bb/c2";
		ftpFile=StringExtend.format("文本-{0}.txt"
				, DateExtend.getDate("yyyyMMddHHmmss"));		
		success = ftp.uploadFile(localFile,ftpDir, ftpFile);		
		assertTrue(success);
		
	}
	@Test
	public void testRemove(){
		boolean success = false;
		String file ="/temp/文本-20170509175507.txt";
		success = ftp.removeFile(file);
		
		assertTrue(success);
	}
	@Test
	public void crateDir(){
		String dir="aa/bb";
		boolean success = ftp.createDir(dir);
		System.out.print(success?"成功":"失败");
		System.out.println(dir);
		
		 dir="aa/bb/c1";
		 success = ftp.createDir(dir);
			System.out.print(success?"成功":"失败");
		 System.out.println(dir);


		 dir="aa/bb/c2";
		 success = ftp.createDir(dir);
			System.out.print(success?"成功":"失败");
		 System.out.println(dir);
		
		assertTrue(success);
	}
	@Test
	public void removeDir(){
		String dir="aa/bb";
		boolean success = ftp.removeDir(dir);
		System.out.print(success?"成功":"失败");
		System.out.println(dir);
		
		 dir="aa/bb/c1";
		 success = ftp.removeDir(dir);
			System.out.print(success?"成功":"失败");
		 System.out.println(dir);


		 dir="aa/bb/c2";
		 success = ftp.removeDir(dir);
			System.out.print(success?"成功":"失败");
		 System.out.println(dir);
		
		assertTrue(success);
	}
	@Test
	public void downloadFile(){
		String ftpDirName="/aa/bb";
		String ftpFileName="img-20170606110355.jpg";
		String localFileFullName=StringExtend.format("D:/Temp/pdf/down/down-{0}.jpg"
				,DateExtend.getDate("yyyyMMddHHmmss"));
		boolean result = ftp.downloadFile(ftpDirName, ftpFileName, localFileFullName);
		assertTrue(result);


		ftpDirName="/";
		ftpFileName="文本.txt";
		localFileFullName=StringExtend.format("D:/Temp/pdf/down/down-{0}.txt"
				,DateExtend.getDate("yyyyMMddHHmmss"));
		result = ftp.downloadFile(ftpDirName, ftpFileName, localFileFullName);
		assertTrue(result);
	}
}

三个工具类:StringExtend,PathExtend,Debug工具类

package me.grass.extend;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.regex.Pattern;

import org.apache.taglibs.standard.lang.jstl.test.beans.PublicInterface2;
import org.springframework.beans.NullValueInNestedPathException;

public class StringExtend {
	/**
	 * 获取换行符,区分不同系统
	 * /r Mac;/n Unix/Linux;/r/n Windows
	 * @return
	 *  @author admin
	 */
	public static String getEnterMark(){
		return System.getProperty("line.separator");
	}
	/**
	 * 清除首位空格
	 * @return
	 */
	public static String trim(String msg)
	{
		if(msg==null)
			return null;
		return msg.trim();
	}
	/**
	 * 字符串内容格式化输出,内部使用{0}\{1}\{2}...为参数占位符
* 参数格式:ArgumentIndex[,FormatType[,FormatStyle]]
* FormatType 取值:number,date,time,choice
* FormatType 样式:如:#.##
* 注:'{' 可输出左花括号(单写左花括号会报错,而单写右花括号将正常输出)
* @param msg 格式化模板 * @param args 不固定参数 * @return */ public static String format(String msg, Object... args) { return java.text.MessageFormat.format(msg, args); } /** * 转换字符串到 * @param num * @return * @author xxj */ public static Integer getInt(String num){ if(num==null || num.trim().isEmpty()) return 0; if(!num.matches("^(\\d|-)\\d{0,9}$")) return 0; try { return Integer.parseInt(num); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return 0; } } public static String getString(Object obj){ return obj == null ? null : obj.toString(); } public static String getString(Integer num){ return getString(num,""); } public static String getString(Integer num,String def){ if(num == null) return def; return num.toString(); } public static String getString(Date date){ return DateExtend.getString(date); } /** * 字符串是否为空 * @param str * @return */ public static boolean isNullOrEmpty(String str){ return str==null || str.trim().isEmpty(); } /** * 比较两个字符串是否相等,忽略大小写 * @param str1 * @param str2 * @return * @author xxj */ public static boolean equalsIgnoreCase(String str1 ,String str2){ String tmp = str1==null?"":str1; return tmp.equalsIgnoreCase(str2); } /** * md5 加密 * @param str * @return * @author xxj 2017年4月24日 */ public static String getMd5(String... str){ if(str==null || str.length==0) return ""; StringBuffer sbr = new StringBuffer(); for(String item : str){ sbr.append(item); } // 生成一个MD5加密计算摘要 MessageDigest md; try { md = MessageDigest.getInstance("MD5"); // 计算md5函数 md.update(sbr.toString().getBytes()); // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符 // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值 return new BigInteger(1, md.digest()).toString(16); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); return ""; } } /** * 删除起始字符 * @param s * @return * @author xxj 2017年4月27日 */ public static String trimStart(String str,String trim){ if(str==null) return null; return str.replaceAll("^("+trim+")+", ""); } /** * 删除末尾字符 * @param s * @return * @author xxj 2017年4月27日 */ public static String trimEnd(String str,String trim){ if(str==null) return null; return str.replaceAll("("+trim+")+$", ""); } /** * 以字符开头 * @param s * @return * @author xxj 2017年4月27日 */ public static boolean startWith(String str,String s){ return str.startsWith(s); } /** * 以字符末尾 * @param s * @return * @author xxj 2017年4月27日 */ public static boolean endWith(String str,String s){ return str.endsWith(s); } /** * 获取 boolean 值(1=true;True=true;) * @param str * @return * @author xxj 2017年5月2日 */ public static boolean getBoolean(String str){ if(isNullOrEmpty(str)) return false; Pattern pattern = Pattern.compile("(1)|(true)", Pattern.CASE_INSENSITIVE); if(pattern.matcher(str).matches()) return true; return false; } /** * 隐藏银行账号后6位 * @param str * @return */ public static String bankAccount(String str) { if(isNullOrEmpty(str)){ return null; } if (str.length()>6) { return str.substring(0, str.length()-6)+"xxxxxx"; } return str; } }


package me.grass.extend;

import java.io.File;

/** 
* 路径扩展
* @author xxj 
* @version 创建时间:2017年4月27日 下午2:45:39
*/
public class PathExtend {
	/**
	 * 合并路径
	 * @param args
	 * @return
	 *  @author xxj 2017年4月27日
	 */
	public static String Combine(String ...args){
		if(args==null || args.length==0)
			return "";
		StringBuffer sbf = new StringBuffer();
		for(String s:args){
//			//纯协议开头不处理,如:http://,d:/,linux首个/不处理
//			if(s.matches("^[a-zA-z]+://$")){
//				sbf.append(s);
//				continue;
//			}
			//首位地址只删除尾部正反斜杠
			if(sbf.length()==0){
				sbf.append(s.replaceAll("/{1,}$|\\{1,}$", ""));
				continue;
			}
				
			if(sbf.length()>0)
				sbf.append("/");
			//去除首尾正反斜杠
			sbf.append(s
					.replaceAll("^/{1,}|^\\{1,}", "")
					.replaceAll("/{1,}$|\\{1,}$", ""));
		}
		
		return sbf.toString();
	}
	/**
	 * 获取应用程序 classpath 路径 
	 * @return
	 *  @author xxj 2017年4月27日
	 */
	public static String getClassPath(){
		return PathExtend.class.getResource("/").getPath();
	} 
	/**
	 * 将相对路径转为绝对路径(相对与 calsspath 的路径)
	 * @param relativePath
	 * @return
	 *  @author xxj 2017年4月27日
	 */
	public static String getAbsolutePath(String relativePath){
		return Combine(getClassPath(),relativePath);
	}
	/**
	 * 获取路径中的目录部分
	 * @param path
	 * @return
	 *  @author xxj 2017年6月15日
	 */
	public static String getDirectory(String path){
		return path.replaceAll("(/)([^/])+\\.([^/])+$", "");
	} 
	/**
	 * 获取路径中的文件名部分
	 * @param path
	 * @return
	 *  @author xxj 2017年6月15日
	 */
	public static String getFileName(String path){
		return path.replaceAll("^.+(/)", "");
	} 
	/**
	 * 创建目录(存在则不创建)
	 * @return
	 *  @author xxj 2017年6月15日
	 */
	public static boolean createDirectory(String dirName){
		File file=new File(dirName);
		if(file.exists())
			return true;
		return file.mkdirs();
	}
}


package me.grass.coder;


import me.grass.extend.StringExtend;

/** 
*
* @author xxj 
* @version 创建时间:2017年4月26日 上午9:52:27
*/
public class Debug {
	/**
	 * 格式化输出,打印信息到控制台
	 * @param format
	 * @param args
	 *  @author xxj 2017年4月26日
	 */
	public static void printFormat(String format,Object ...args){
		if(args==null){
			System.out.println(format);
		}
		System.out.println(java.text.MessageFormat.format(format, args));
	}
	/**
	 * 格式化输出,打印信息到控制台
	 * @param format
	 * @param args
	 *  @author xxj 2017年4月26日
	 */
	public static void print(Object ...msg){
		if(msg==null){
			return;
		}
		for(Object x:msg){
			System.out.print(x);
//			System.out.print(' ');
		}
		System.out.println();
	}
	/**
	 * 格式化输出,打印信息到控制台
	 * @param format
	 * @param args
	 *  @author xxj 2017年4月26日
	 */
	public static void println(Object ...msg){
		if(msg==null){
			return;
		}
		for(Object x:msg)
			System.out.println(x);
	}
	/**
	 * 打印当前线程的调用堆栈
	 * 
	 *  @author xxj 2017年4月26日
	 */
	public static void printTrack(){
		StackTraceElement[] st = Thread.currentThread().getStackTrace();
		if(st==null){
			System.out.println("无堆栈...");
			return;
		}
		StringBuffer sbf =new StringBuffer();
		sbf.append(StringExtend.format("调用堆栈[{0}]:",StringExtend.getString(new java.util.Date())));		
		for(StackTraceElement e:st){
			sbf.append(StringExtend.format(" {0}.{1}() {2} <- {3}"
					,e.getClassName()
					,e.getMethodName()
					,e.getLineNumber()
					,StringExtend.getEnterMark()));
		}
		System.out.println(sbf.toString());
	}
}




你可能感兴趣的:(java)