文件压缩及上传FTP服务器简单应用(实践篇)
前言
时隔这么久我又回来了,最近忙里偷闲写了一个FTP上传文件的demo,用于上传公司发布的USDK服务的log文件,之前发布的USDK在客户那儿出现了不少bug,而解决这些bug需要我们的辛勤测试人员根据客户描述的现象复现修正,效率极低;那干脆就把现场log直接上传就好了呗~(不禁吐槽公司这么久了连个文件上传的管理服务器都没有,唉~);咳咳,言归正传,这个demo主要包含了三点:生成log文件/log文件的压缩/上传服务器,请看下文!
正文
生成log文件
这一趴其实没什么好讲的,正常的IO文件操作,所以就直接上代码了:代码片
/*** 保存log到文件** @param tag log的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 1
Thread.currentThread().getStackTrace()
//method 2
new Throwable().getStackTrace()
不同之处在于方法一会先打印生成使用方法,具体见下(部分数据,使用方法getClassName和getMethodName打印):
--------------------------Throwable-------------------
com.topwise.compress.utils.LogUtil;getLogTag
com.topwise.compress.utils.LogUtil;d
com.topwise.compress.MainActivity;onClick
-------------------------currentThread---------------
dalvik.system.VMStack;getThreadStackTrace
java.lang.Thread;getStackTrace
com.topwise.compress.utils.LogUtil;getLogTag
com.topwise.compress.utils.LogUtil;d
com.topwise.compress.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"/>
[参考博文链接]
https://blog.csdn.net/weixin_40759186/article/details/79423396
[下载FTP-lib包链接]
链接: https://pan.baidu.com/s/1t_HqSqnmTyVDMOk8Ko_voQ&shfl=shareset 提取码: e58b
文件压缩及上传FTP服务器简单应用(实践篇)相关推荐
- 自动备份网站和数据库打包并上传FTP服务器并删除前30天文件
自动备份网站和数据库打包并上传FTP服务器并删除前30天文件 @echo off<nul 3>nul Set nowdate=%date:~0,10% set nowdate=%nowda ...
- mac 上传ftp服务器文件夹权限,mac 访问 ftp服务器文件夹权限
mac 访问 ftp服务器文件夹权限 内容精选 换一换 在"云服务器列表"页,单击下拉按钮展开会话列表,查看会话连接状态,出现"关闭应用失败"的异常.将鼠标移动 ...
- mac 上传ftp服务器文件大小,mac与windows通过ftp传输文件
1.两个系统相互传文件,比较通用的方式是用QQ,两台电脑一台各登陆一个qq,发文件就行了,在同一个网段时,qq会自动转换为按局域网的方式传输. 2.本人不愿安装qq,以ftp方式进行传输,先在wndo ...
- C#对.CSV格式的文件--逗号分隔值文件 的读写操作及上传ftp服务器操作方法总结(转)
前言 公司最近开发需要将数据保存到.csv文件(逗号分隔值 文件)中然后上传到ftp服务器上,供我们系统还有客户系统调用,之前完全没有接触过这个,所以先来看看百度的解释:逗号分隔值(Comma-Sep ...
- ftp 服务器 单文件上传,ftp 服务器 单文件上传
ftp 服务器 单文件上传 内容精选 换一换 本文介绍如何在 Linux 系统的本地机器上使用 FTP 服务,将文件从本地上传到云服务器中.已在待上传文件的云服务器中搭建 FTP 服务.如果您的云服务 ...
- ftp服务器批量上传文件,bat批量上传ftp文件到服务器
bat批量上传ftp文件到服务器 内容精选 换一换 CDM支持周期性自动将新增文件上传到OBS,不需要写代码,也不需要用户频繁手动上传即可使用OBS的海量存储能力进行文件备份.这里以CDM周期性备份F ...
- 巧用shell+rsync服务实现日志自动过滤处理压缩并上传日志服务器,自动分类
分享一个自己很早以前先写的日志存储方案,简单实用,业务端上传完日志后自己清除已经上传过的日志,连清空间的工作都省了.(未完) 找出所有部署目录下的日志文件夹,压缩指定文件与文件夹,不改变日志压缩路径( ...
- 图片文件压缩并上传至阿里云OSS
图片处理 Thumbnails 在进行Java开发时可以使用Thumbnails工具类对图片进行处理,旋转.裁剪.格式转换.加水印等. 使用步骤 导包 <dependency><gr ...
- 返回图片_Vue 图片压缩并上传至服务器
日常开发中经常会遇到上传图片的需求,随着手机的蓬勃发展,现在拍出来的照片分辨率越来越高,随之带来的问题就是图片占用空间越来越大,如果我们直接上传图片可能就会浪费很大一笔资源,本文主要讲解基于 Vue ...
最新文章
- java script 6 折线_Java Script学习 6(转)
- Ubuntu使用——23(dock的美化)
- 解决Windows 2003中不允许的父路径Active Server Pages错误'ASP 0131'的方法
- php 怎么实现收藏功能,php收藏功能如何实现
- python if main_Python:if __name__ == '__main__'
- python日期格式转换_python中有关时间日期格式转换问题
- 农村义务教育经费保障机制改革校长应知应会卡
- Mint-UI组件 MessageBox为prompt 添加判断条件
- python numpy安装步骤-NumPy 安装
- 编程基本功:给不同的电脑贴标
- 网站被黑被劫持跳转的症状与木马代码清除
- 2020 年 Python 知识清单(数据分析)
- 使用代理爬去微信公众号_Python3网络爬虫开发实战之使用代理爬取微信公众号文章...
- pci规划的三个原则_LTE中PCI规划目的和原则
- VC++6.0 MFC显示模态对话框和非模态对话框
- 大数据Kudu使用方法
- lrd热加载方式启动本地web服务(我用于从github把别人服务器代码拉倒本地去搭建自己的网络服务)
- 10类职业人士最容易受到失眠困扰
- albus就是要第一个出场
- ZKNUOJ 1015
热门文章
- PyQt5表格控件QTableWidget
- 在线图片上传 POST文件
- python画泡泡图片例子
- 抖音上的时钟屏保,被我改造完用来表白
- 开机读不了bios,提示为 press del to enter setup, esc to enter boot me
- excel满足其中任何一个条件的筛选
- vue npm run dev 提示To install them, you can run: npm install --save @/url
- 衡水东方计算机学校地址,衡水东方计算机学校
- GitHub也能CI/CD了 如何使用GitHub的Action?
- 中景合天部分工作内容摘要