前言

时隔这么久我又回来了,最近忙里偷闲写了一个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;}

这里需解释的是

  1. ftpClient.enterLocalPassiveMode():FTP分主动模式和被动模式,关于主动模式和被动模式在补充中做了相关的简单说明;由于很多客户端在防火墙内,开放端口给服务器端用比较困难,所以用被动模式的时候比较多;设置模式需要在登录之前设置才会生效;
  2. 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了,到这里基本上就结束了,是不是很简单啊~

补充

  1. FTP主动模式和被动模式解释:
    这两种模式发起连接的方向截然相反,主动模式是从服务器端向客户端发起连接;被动模式是客户端向服务器端发起连接。
      PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,客户端在命令链路上用PORT命令告诉服务器:“我打开了***X端口,你过来连接我”。于是服务器从20端口向客户端的***X端口发送连接请求,建立一条数据链路来传送数据。
      PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端:“我打开了***X端口,你过来连接我”。于是客户端向服务器的***X端口发送连接请求,建立一条数据链路来传送数据。
      从上面可以看出,两种方式的命令链路连接方法是一样的,而数据链路的建立方法就完全不同。
  2. 关于FTP的断点续传,实际上是有相关接口支持的,使用断点续传需要注意的是:1)服务器支持断点续传2)客户端要知道使用REST等一系列指令来作断点续传;断点续传所使用的方法主要是setRestartOffset设置断点位置,具体实现就让小伙伴们自己尝试了。

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

续集

  1. 最近(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服务器简单应用(实践篇)相关推荐

  1. 自动备份网站和数据库打包并上传FTP服务器并删除前30天文件

    自动备份网站和数据库打包并上传FTP服务器并删除前30天文件 @echo off<nul 3>nul Set nowdate=%date:~0,10% set nowdate=%nowda ...

  2. mac 上传ftp服务器文件夹权限,mac 访问 ftp服务器文件夹权限

    mac 访问 ftp服务器文件夹权限 内容精选 换一换 在"云服务器列表"页,单击下拉按钮展开会话列表,查看会话连接状态,出现"关闭应用失败"的异常.将鼠标移动 ...

  3. mac 上传ftp服务器文件大小,mac与windows通过ftp传输文件

    1.两个系统相互传文件,比较通用的方式是用QQ,两台电脑一台各登陆一个qq,发文件就行了,在同一个网段时,qq会自动转换为按局域网的方式传输. 2.本人不愿安装qq,以ftp方式进行传输,先在wndo ...

  4. C#对.CSV格式的文件--逗号分隔值文件 的读写操作及上传ftp服务器操作方法总结(转)

    前言 公司最近开发需要将数据保存到.csv文件(逗号分隔值 文件)中然后上传到ftp服务器上,供我们系统还有客户系统调用,之前完全没有接触过这个,所以先来看看百度的解释:逗号分隔值(Comma-Sep ...

  5. ftp 服务器 单文件上传,ftp 服务器 单文件上传

    ftp 服务器 单文件上传 内容精选 换一换 本文介绍如何在 Linux 系统的本地机器上使用 FTP 服务,将文件从本地上传到云服务器中.已在待上传文件的云服务器中搭建 FTP 服务.如果您的云服务 ...

  6. ftp服务器批量上传文件,bat批量上传ftp文件到服务器

    bat批量上传ftp文件到服务器 内容精选 换一换 CDM支持周期性自动将新增文件上传到OBS,不需要写代码,也不需要用户频繁手动上传即可使用OBS的海量存储能力进行文件备份.这里以CDM周期性备份F ...

  7. 巧用shell+rsync服务实现日志自动过滤处理压缩并上传日志服务器,自动分类

    分享一个自己很早以前先写的日志存储方案,简单实用,业务端上传完日志后自己清除已经上传过的日志,连清空间的工作都省了.(未完) 找出所有部署目录下的日志文件夹,压缩指定文件与文件夹,不改变日志压缩路径( ...

  8. 图片文件压缩并上传至阿里云OSS

    图片处理 Thumbnails 在进行Java开发时可以使用Thumbnails工具类对图片进行处理,旋转.裁剪.格式转换.加水印等. 使用步骤 导包 <dependency><gr ...

  9. 返回图片_Vue 图片压缩并上传至服务器

    日常开发中经常会遇到上传图片的需求,随着手机的蓬勃发展,现在拍出来的照片分辨率越来越高,随之带来的问题就是图片占用空间越来越大,如果我们直接上传图片可能就会浪费很大一笔资源,本文主要讲解基于 Vue ...

最新文章

  1. java script 6 折线_Java Script学习 6(转)
  2. Ubuntu使用——23(dock的美化)
  3. 解决Windows 2003中不允许的父路径Active Server Pages错误'ASP 0131'的方法
  4. php 怎么实现收藏功能,php收藏功能如何实现
  5. python if main_Python:if __name__ == '__main__'
  6. python日期格式转换_python中有关时间日期格式转换问题
  7. 农村义务教育经费保障机制改革校长应知应会卡
  8. Mint-UI组件 MessageBox为prompt 添加判断条件
  9. python numpy安装步骤-NumPy 安装
  10. 编程基本功:给不同的电脑贴标
  11. 网站被黑被劫持跳转的症状与木马代码清除
  12. 2020 年 Python 知识清单(数据分析)
  13. 使用代理爬去微信公众号_Python3网络爬虫开发实战之使用代理爬取微信公众号文章...
  14. pci规划的三个原则_LTE中PCI规划目的和原则
  15. VC++6.0 MFC显示模态对话框和非模态对话框
  16. 大数据Kudu使用方法
  17. lrd热加载方式启动本地web服务(我用于从github把别人服务器代码拉倒本地去搭建自己的网络服务)
  18. 10类职业人士最容易受到失眠困扰
  19. albus就是要第一个出场
  20. ZKNUOJ 1015

热门文章

  1. PyQt5表格控件QTableWidget
  2. 在线图片上传 POST文件
  3. python画泡泡图片例子
  4. 抖音上的时钟屏保,被我改造完用来表白
  5. 开机读不了bios,提示为 press del to enter setup, esc to enter boot me
  6. excel满足其中任何一个条件的筛选
  7. vue npm run dev 提示To install them, you can run: npm install --save @/url
  8. 衡水东方计算机学校地址,衡水东方计算机学校
  9. GitHub也能CI/CD了 如何使用GitHub的Action?
  10. 中景合天部分工作内容摘要