1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 文件压缩及上传FTP服务器简单应用(实践篇)

文件压缩及上传FTP服务器简单应用(实践篇)

时间:2019-04-11 08:36:08

相关推荐

文件压缩及上传FTP服务器简单应用(实践篇)

前言

时隔这么久我又回来了,最近忙里偷闲写了一个FTP上传文件的demo,用于上传公司发布的USDK服务的log文件,之前发布的USDK在客户那儿出现了不少bug,而解决这些bug需要我们的辛勤测试人员根据客户描述的现象复现修正,效率极低;那干脆就把现场log直接上传就好了呗~(不禁吐槽公司这么久了连个文件上传的管理服务器都没有,唉~);咳咳,言归正传,这个demo主要包含了三点:生成log文件/log文件的压缩/上传服务器,请看下文!

正文

生成log文件

这一趴其实没什么好讲的,正常的IO文件操作,所以就直接上代码了:代码片

/*** 保存log到文件** @param taglog的tag值* @param finalMsg log的内容*/private static void writeToLog(String tag, String finalMsg) {File logFile = new File(LOG_FILE_PATH, LOG_FILE_NAME);File parentFile = logFile.getParentFile();if (!parentFile.exists()) {if (!parentFile.mkdirs()) {return;}}//delete file if over MAX_LOG_SIZE if (logFile.exists() && logFile.length() > MAX_LOG_SIZE) {logFile.delete();}if (!logFile.exists()) {try {if (!logFile.createNewFile()) {return;}} catch (IOException e) {e.printStackTrace();}}BufferedOutputStream outputStream = null;try {outputStream = new BufferedOutputStream(new FileOutputStream(logFile, true));String content = FtpCommonUtils.getTagTime(DATE_FORMAT) + " " + tag + " " + finalMsg + "\n";outputStream.write(content.getBytes());outputStream.flush();} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}

我也没对文件进行时间的划分,单个log文件就够用,只是对log文件的大小进行了限制,这里打log的方法稍微进行了封装,代码片

public static void d(String msg) {String tag = getLogTag();String finalMsg = buildMsg(msg);if (curLevel <= TAG_LEVEL_D) {Log.d(TAG + " " + tag, finalMsg);}if (isWriteLogFile) {writeToLog(tag, finalMsg);}}/*** 返回包含调用方法名的log信息** @param msg 原始传入的信息* @return 包含调用方法名的log信息*/private static String buildMsg(String msg) {StackTraceElement[] element = new Throwable().fillInStackTrace().getStackTrace();String methodName = element[2].getMethodName();return methodName + " " + msg;}/*** 获取当前打印的类名** @return 当前调用的类名*/private static String getLogTag() {StackTraceElement[] element = new Throwable().fillInStackTrace().getStackTrace();String fullName = element[2].getClassName();String simpleName = fullName;if (fullName != null && fullName.contains(".")) {String[] buffer = fullName.split("\\.");simpleName = buffer[buffer.length - 1];}return simpleName;}

这里直接通过方法栈找到调用封装打印接口的类和方法;使用了Throwable()类获取当前方法栈的内容,获取方法栈的方法有两种:

//method 1Thread.currentThread().getStackTrace()//method 2new Throwable().getStackTrace()

不同之处在于方法一会先打印生成使用方法,具体见下(部分数据,使用方法getClassName和getMethodName打印):

--------------------------Throwable-------------------

press.utils.LogUtil;getLogTag

press.utils.LogUtil;d

press.MainActivity;onClick

-------------------------currentThread---------------

dalvik.system.VMStack;getThreadStackTrace

java.lang.Thread;getStackTrace

press.utils.LogUtil;getLogTag

press.utils.LogUtil;d

press.MainActivity;onClick

log文件的压缩

压缩文件使用压缩文件流,主要的类是ZipOutputStream ZipEntry,可实现压缩操作,代码如下代码片

/*** 压缩文件方法** @param srcFileName 待压缩文件(夹)路径* @return 返回压缩后的文件路径*/String FileZip(String[] srcFileName) {LogUtil.d("src file name: " + srcFileName);//create zip fileFile zipFile = getZipFile();if (zipFile == null) {return null;}//find src files File[] srcFiles = getSrcFiles(srcFileName);if (srcFiles == null) {return null;}ZipOutputStream zipOutputStream = null;FileInputStream fileInputStream = null;try {zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));for (File srcFile : srcFiles) {// 将源文件数组中的当前文件读入 FileInputStream 流中fileInputStream = new FileInputStream(srcFile);// 实例化 ZipEntry 对象,源文件数组中的当前文件ZipEntry zipEntry = new ZipEntry(srcFile.getName());zipOutputStream.putNextEntry(zipEntry);// 该变量记录每次真正读的字节个数int len;// 定义每次读取的字节数组byte[] buffer = new byte[1024];while ((len = fileInputStream.read(buffer)) > 0) {zipOutputStream.write(buffer, 0, len);}}} catch (IOException e) {e.printStackTrace();return null;} finally {try {if (zipOutputStream != null) {zipOutputStream.closeEntry();zipOutputStream.close();}if (fileInputStream != null) {fileInputStream.close();}} catch (IOException e) {e.printStackTrace();}}return zipFile.getAbsolutePath();}

生成压缩文件使用putNextEntry方法,读取压缩文件使用getNextEntry,这个也是正常的IO流操作。

这里在查找log文件夹下我需要的log文件时,使用了文件过滤器:代码块

private class ZipFileFileFilter implements FileFilter {@Overridepublic boolean accept(File pathname) {return pathname.getName().endsWith(".log") || pathname.getName().endsWith(".jpg");}}

FileFilter这个接口的使用只要实现其accept方法,把你需要的过滤的文件限制写好,调用file.listFiles(new ZipFileFileFilter())即可过滤出你想要的文件;

上传文件到FTP服务器

使用FTP需引入lib包(commons-net-3.3.jar,下载链接见文章底部),主要使用FTPClient这个类进行文件的上传下载操作,上传需要连接登录/上传文件/断开链接三步;

连接登陆

主要代码如下代码块

/*** 连接登录FTP服务器** @return boolean 连接结果*/boolean ftpConnect() {LogUtil.d("start ftpConnect");boolean result = false;try {ftpClient = new FTPClient();//set timeoutftpClient.setConnectTimeout(TIME_OUT / 2);ftpClient.setDataTimeout(TIME_OUT);//start connectftpClient.connect(FTP_SERVER);//get connect resultresult = FTPReply.isPositiveCompletion(ftpClient.getReplyCode());if (result) {//set passive modeftpClient.enterLocalPassiveMode();//log inftpClient.login(FTP_USERNAME, FTP_PASSWORD);//set filetype, here set bytearrayftpClient.setFileType(FTP.BINARY_FILE_TYPE);}} catch (Exception e) {e.printStackTrace();LogUtil.e("error: " + e);} finally {if (!result) {ftpDisConnect();}}return result;}

这里需解释的是

ftpClient.enterLocalPassiveMode():FTP分主动模式和被动模式,关于主动模式和被动模式在补充中做了相关的简单说明;由于很多客户端在防火墙内,开放端口给服务器端用比较困难,所以用被动模式的时候比较多;设置模式需要在登录之前设置才会生效;ftpClient.setFileType(FTP.BINARY_FILE_TYPE):设置文件传输方式,传输方式主要有ASCII和二进制传输两种方式,我的理解是拷贝文本文件可用ASCII方式,一般都用二进制传输方式传输;

上传文件

上传文件其实很简单,只需要调用ftpClient.storeFile方法就可以了,部分代码如下代码块

/*** 文件上传ftp** @param srcFile 待上传文件* @param remoteFileName ftp文件名称* @return 上传结果*/int uploadFile(String srcFile, String remoteFileName) {LogUtil.d("uploadFile: " + srcFile + ";remoteFileName: " + remoteFileName);if (srcFile == null || remoteFileName == null) {return FtpCommonUtils.INPUT_PARAM_ERROR;}if (!ftpClient.isConnected()) {LogUtil.d("ftpClient not connected!");return FtpCommonUtils.FTP_NOT_CONNECTED;}FileInputStream stream = null;boolean uploadRet = false;try {stream = new FileInputStream(srcFile);uploadRet = ftpClient.storeFile(remoteFileName, stream);stream.close();} catch (IOException e) {e.printStackTrace();LogUtil.e("error: " + e);} finally {try {if (stream != null) {stream.close();}} catch (IOException e) {e.printStackTrace();}}return uploadRet ? FtpCommonUtils.RETURN_SUCCESS : FtpCommonUtils.FTP_UPLOAD_FAIL;}

ftpClient.storeFile方法的入参第一个是服务端的文件名称,第二个是本地文件的IO流;注意的是服务端的文件名不要带中文,也不要带:(中英文都不行)等特殊字符(我就是吃了:的亏,想在名称中附上上传时间,结果查了好些时间)。

断开FTP连接

/*** 断开FTP链接*/void ftpDisConnect() {LogUtil.d("ftpDisConnect");if (ftpClient != null && ftpClient.isConnected()) {try {ftpClient.logout();ftpClient.disconnect();} catch (IOException e) {e.printStackTrace();}}}

此demo所需要的权限:读写sd卡 internet权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.INTERNET"/>

OK了,到这里基本上就结束了,是不是很简单啊~

补充

FTP主动模式和被动模式解释:

这两种模式发起连接的方向截然相反,主动模式是从服务器端向客户端发起连接;被动模式是客户端向服务器端发起连接。

PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链路上用PORT命令告诉服务器:“我打开了***X端口,你过来连接我”。于是服务器从20端口向客户端的***X端口发送连接请求,建立一条数据链路来传送数据。

PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端:“我打开了***X端口,你过来连接我”。于是客户端向服务器的***X端口发送连接请求,建立一条数据链路来传送数据。

从上面可以看出,两种方式的命令链路连接方法是一样的,而数据链路的建立方法就完全不同。关于FTP的断点续传,实际上是有相关接口支持的,使用断点续传需要注意的是:1)服务器支持断点续传2)客户端要知道使用REST等一系列指令来作断点续传;断点续传所使用的方法主要是setRestartOffset设置断点位置,具体实现就让小伙伴们自己尝试了。

好了,本文到这儿就基本结束了,有什么错误的地方劳烦各位大佬评论指正!

续集

最近(19-11-07)又做了一个过滤系统log的需求,使用的方法代码如下:

public void saveSystemLog(File logFile, long fileLimit) {Log.d(TAG, "saveSystemLog logFile: " + logFile + ";fileLimit: " + fileLimit);ArrayList<String> list = new ArrayList<>();list.add("logcat");//logcat -v time -s *:Ilist.add("-v");list.add("time");list.add("-s");list.add("*:I");ArrayList<String> clearList = new ArrayList<>();clearList.add("logcat");clearList.add("-c");String[] order = list.toArray(new String[list.size()]);String[] clearOrder = clearList.toArray(new String[clearList.size()]);Process process = null;try {process = Runtime.getRuntime().exec(order);Runtime.getRuntime().exec(clearOrder);} catch (IOException e) {e.printStackTrace();}if (process == null) {return;}FileOutputStream outputStream = null;InputStream inputStream = null;try {outputStream = new FileOutputStream(logFile, true);inputStream = process.getInputStream();int line;byte[] buffer = new byte[1024];while ((line = inputStream.read(buffer)) > 0 && !isStop) {if (fileLimit > 0 && logFile.length() >= fileLimit) {break;}outputStream.write(buffer, 0, line);outputStream.flush();}} catch (IOException e) {Log.d(TAG, "error: " + e);e.printStackTrace();} finally {try {if (outputStream != null) {outputStream.close();}if (inputStream != null) {inputStream.close();}} catch (IOException e) {Log.d(TAG, "error: " + e);e.printStackTrace();}}}

使用Runtime类的exec执行adb命令获取,你可以在电脑上执行adb logcat --help查看命令使用,便于你查找你需要使用的方法;

adb logcat -v time -s *:I

-v time:需要log自带时间打印 -s为过滤使用,后面跟过滤条件(Tag:TAG级别),*代表无过滤tag,I代表过滤info级别及以上的log;

adb logcat -c : 清除日志缓存

权限说明:获取系统log目前需要程序为系统权限,即进行系统签名才可以,并且需要声明权限

<uses-permission android:name="android.permission.READ_LOGS"/>

[参考博文链接]

/weixin_40759186/article/details/79423396

[下载FTP-lib包链接]

链接: /s/1t_HqSqnmTyVDMOk8Ko_voQ&shfl=shareset 提取码: e58b

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。