zoukankan      html  css  js  c++  java
  • 【FTP】FTP文件上传下载-支持断点续传

    • Jar包:apache的commons-net包;
    • 支持断点续传
    • 支持进度监控(有时出不来,搞不清原因)

    相关知识点

    • 编码格式: UTF-8等;
    • 文件类型: 包括[BINARY_FILE_TYPE(常用)]和[ASCII_FILE_TYPE]两种;
    • 数据连接模式:一般使用LocalPassiveMode模式,因为大部分客户端都在防火墙后面;
                  1. LocalPassiveMode:服务器端打开数据端口,进行数据传输;
                  2. LocalActiveMode:客户端打开数据端口,进行数据传输;
    • 系统类型:UNIX/WINDOWS等,默认为Unix

    流程

    • 步骤1: 创建FTPClient对象,设置ftpClient属性:如编码格式、连接超时、文件上传下载进度监听器等;
    • 步骤2: 使用ftpClient连接远程server:connect();
    • 步骤3: 获取connect()的返回码getReplyCode(),判断是否连接成功:isPositiveCompletion();
    • 步骤4: 登录远程server:login(),并转到相应目录,必要时要递归创建目录;
    • 步骤5: 设置ftpClient属性:如缓存大小、文件类型、超时时间、数据连接模式等;
    • 步骤6: ftp相关操作:如文件上传、下载等;
    • 步骤7: 断开连接,释放资源:logout()/disconnect();

    程序

    FTP连接和登录



    文件上传



    文件下载


    测试程序


    完整程序

    1. package com.sssppp.Communication;
    2. import java.io.File;
    3. import java.io.FileOutputStream;
    4. import java.io.IOException;
    5. import java.io.InputStream;
    6. import java.io.OutputStream;
    7. import java.io.PrintWriter;
    8. import java.io.RandomAccessFile;
    9. import org.apache.commons.net.PrintCommandListener;
    10. import org.apache.commons.net.ftp.FTP;
    11. import org.apache.commons.net.ftp.FTPClient;
    12. import org.apache.commons.net.ftp.FTPClientConfig;
    13. import org.apache.commons.net.ftp.FTPFile;
    14. import org.apache.commons.net.ftp.FTPReply;
    15. import org.apache.commons.net.io.CopyStreamEvent;
    16. import org.apache.commons.net.io.CopyStreamListener;
    17. /**
    18. * FTP进行文件上传和下载;
    19. * 支持断点续传;
    20. */
    21. public final class FTPUtil {
    22. private final FTPClient ftp = new FTPClient();
    23. /**
    24. *
    25. * @param hostname
    26. * 如:IP
    27. * @param port
    28. * @param username
    29. * @param password
    30. * @return
    31. * @throws IOException
    32. */
    33. public boolean connect(String hostname, int port, String username,
    34. String password) throws IOException {
    35. boolean debug = false;
    36. if (debug) {
    37. // 设置将过程中使用到的命令输出到控制台
    38. this.ftp.addProtocolCommandListener(new PrintCommandListener(
    39. new PrintWriter(System.out), true));
    40. }
    41. //设置系统类型
    42. final FTPClientConfig config = new FTPClientConfig(
    43. FTPClientConfig.SYST_UNIX);
    44. this.ftp.configure(config);
    45. try {
    46. this.ftp.connect(hostname, port);
    47. if (!FTPReply.isPositiveCompletion(this.ftp.getReplyCode())) {
    48. this.ftp.disconnect();
    49. System.err.println("FTP server refused connection.");
    50. return false;
    51. }
    52. } catch (IOException e) {
    53. if (this.ftp.isConnected()) {
    54. try {
    55. this.ftp.disconnect();
    56. } catch (IOException f) {
    57. }
    58. }
    59. System.err.println("Could not connect to server.");
    60. e.printStackTrace();
    61. return false;
    62. }
    63. if (!this.ftp.login(username, password)) {
    64. this.ftp.logout();
    65. System.err.println("Could not login to server.");
    66. return false;
    67. }
    68. return true;
    69. }
    70. public void disconnect() throws IOException {
    71. if (this.ftp.isConnected()) {
    72. try {
    73. this.ftp.logout();
    74. this.ftp.disconnect();
    75. } catch (IOException f) {
    76. }
    77. }
    78. }
    79. /**
    80. *
    81. * @param absSrcFileName
    82. * @param destDir
    83. * @param destFileName
    84. * @throws IOException
    85. */
    86. public void upLoadByFtp(String absSrcFileName, String destDir,
    87. String destFileName) throws IOException {
    88. // 创建并转到工作目录
    89. String absDstDir = this.ftp.printWorkingDirectory() + "/" + destDir;
    90. absDstDir = absDstDir.replaceAll("//", "/");
    91. createDirectory(absDstDir, this.ftp);
    92. // 设置各种属性
    93. this.ftp.setFileType(FTP.BINARY_FILE_TYPE);
    94. // Use passive mode as default because most of us are behind firewalls these days.
    95. this.ftp.enterLocalPassiveMode();
    96. this.ftp.setControlEncoding("utf-8");
    97. this.ftp.setBufferSize(1024);
    98. // 进度监听
    99. File srcFile = new File(absSrcFileName);
    100. this.ftp.setCopyStreamListener(new MyCopyStreamListener(srcFile.length()));
    101. FTPFile[] files = this.ftp.listFiles(destFileName);
    102. if (files.length == 1) {// 断点续传
    103. long dstFileSize = files[0].getSize();
    104. if (srcFile.length() <= dstFileSize) {// 文件已存在
    105. return;
    106. }
    107. boolean b = uploadFile(destFileName, srcFile, this.ftp, dstFileSize);
    108. if (!b) {// 如果断点续传没有成功,则删除服务器上文件,重新上传
    109. if (this.ftp.deleteFile(destFileName)) {
    110. uploadFile(destFileName, srcFile, this.ftp, 0);
    111. }else {
    112. System.err.println("Delete file fail.");
    113. }
    114. }
    115. } else {
    116. uploadFile(destFileName, srcFile, this.ftp, 0);
    117. }
    118. }
    119. /**
    120. *
    121. * @param remoteFileName
    122. * @param localFileName
    123. * @throws IOException
    124. */
    125. public void downLoadByFtp(String remoteFileName, String localFileName)
    126. throws IOException {
    127. InputStream input = null;
    128. FileOutputStream fos = null;
    129. // 设置各种属性
    130. this.ftp.setBufferSize(1024);
    131. this.ftp.setDataTimeout(1000 * 10);
    132. this.ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
    133. this.ftp.enterLocalPassiveMode();
    134. // 判断远程文件是否存在
    135. FTPFile[] files = this.ftp.listFiles(remoteFileName);
    136. if (files.length != 1) {
    137. System.err.println("Remote file not exist.");
    138. return;
    139. }
    140. //进度监听
    141. long remoteSize = files[0].getSize();
    142. this.ftp.setCopyStreamListener(new MyCopyStreamListener(remoteSize));
    143. File file = new File(localFileName);
    144. if (file.exists()) {
    145. long localSize = file.length();
    146. if (localSize >= remoteSize) {
    147. return;
    148. }
    149. System.out.println("@@@Break point download.@@@");
    150. fos = new FileOutputStream(file, true);// append模式
    151. this.ftp.setRestartOffset(localSize);
    152. } else {
    153. fos = new FileOutputStream(file); // override模式
    154. }
    155. input = this.ftp.retrieveFileStream(remoteFileName);
    156. byte[] b = new byte[8192];
    157. int n = 0;
    158. while (-1 != (n = input.read(b))) {
    159. if (Thread.currentThread().isInterrupted()) {
    160. break;
    161. }
    162. fos.write(b, 0, n);
    163. }
    164. if (input != null) {
    165. input.close();
    166. }
    167. if (fos != null) {
    168. fos.flush();
    169. fos.close();
    170. }
    171. if (!this.ftp.completePendingCommand()) {
    172. System.err.println("Download file fail.");
    173. this.ftp.logout();
    174. this.ftp.disconnect();
    175. }
    176. }
    177. /**
    178. *
    179. * @param destFileName
    180. * @param srcFile
    181. * @param ftpClient
    182. * @param dstFileSize 文件写入的起始位置; >0:表示断点续传,<=0:表示上传新文件
    183. * @return
    184. * @throws IOException
    185. */
    186. private boolean uploadFile(String destFileName, File srcFile,
    187. FTPClient ftpClient, long dstFileSize) throws IOException {
    188. RandomAccessFile input = null;
    189. OutputStream fout = null;
    190. input = new RandomAccessFile(srcFile, "r"); // 只读模式
    191. if (dstFileSize > 0) {// 断点续传
    192. fout = ftpClient.appendFileStream(destFileName);
    193. input.seek(dstFileSize);
    194. ftpClient.setRestartOffset(dstFileSize);
    195. } else {
    196. fout = ftpClient.storeFileStream(destFileName);
    197. }
    198. byte[] b = new byte[8192]; // 缓存大小
    199. int n = 0;
    200. while (-1 != (n = input.read(b))) {
    201. if (Thread.currentThread().isInterrupted()) {
    202. break;
    203. }
    204. fout.write(b, 0, n);
    205. }
    206. if (input != null) {
    207. input.close();
    208. }
    209. if (fout != null) {
    210. fout.flush();
    211. fout.close();
    212. }
    213. if (!ftpClient.completePendingCommand()) {
    214. System.err.println("Upload file fail.");
    215. ftpClient.logout();
    216. ftpClient.disconnect();
    217. return false;
    218. }
    219. return true;
    220. }
    221. /**
    222. * FTP服务器上创建并转到工作目录
    223. *
    224. * @param relativePath
    225. * 相对工作路径,不包含文件名:如 dd/11/22/33
    226. * @param ftpClient
    227. * 录创建是否成功
    228. * @return
    229. * @throws IOException
    230. */
    231. private boolean createDirectory(String relativePath, FTPClient ftpClient)
    232. throws IOException {
    233. if (!relativePath.startsWith("/")) {
    234. relativePath = "/" + relativePath;
    235. }
    236. String dir = (ftpClient.printWorkingDirectory().equals("/") ? ""
    237. : ftpClient.printWorkingDirectory()) + relativePath;
    238. if (!ftpClient.changeWorkingDirectory(dir)) {
    239. //目录不存在,则创建各级目录
    240. for (String subDir : relativePath.split("/")) {
    241. if (!subDir.equals("")) {
    242. String newDir = ftpClient.printWorkingDirectory() + "/"
    243. + subDir;
    244. ftpClient.mkd(newDir);
    245. if (!ftpClient.changeWorkingDirectory(newDir)) {
    246. return false;
    247. }
    248. }
    249. }
    250. }
    251. return true;
    252. }
    253. /**
    254. * 进度监听器
    255. */
    256. private class MyCopyStreamListener implements CopyStreamListener {
    257. private long totalSize = 0;
    258. private long percent = -1; // 进度
    259. /**
    260. * 文件的总大小
    261. * @param totalSize
    262. */
    263. public MyCopyStreamListener(long totalSize) {
    264. super();
    265. this.totalSize = totalSize;
    266. }
    267. @Override
    268. public void bytesTransferred(CopyStreamEvent event) {
    269. bytesTransferred(event.getTotalBytesTransferred(),
    270. event.getBytesTransferred(), event.getStreamSize());
    271. }
    272. //totalBytesTransferred:当前总共已传输字节数;
    273. //bytesTransferred:最近一次传输字节数
    274. @Override
    275. public void bytesTransferred(long totalBytesTransferred,
    276. int bytesTransferred, long streamSize) {
    277. if (percent >= totalBytesTransferred * 100 / totalSize) {
    278. return;
    279. }
    280. percent = totalBytesTransferred * 100 / totalSize;
    281. System.out.println("Completed " + totalBytesTransferred + "("
    282. + percent + "%) out of " + totalSize + ".");
    283. }
    284. }
    285. public static void main(String[] args) throws IOException {
    286. String hostname = "10.180.137.241";
    287. String username = "xxx";
    288. String password = "xxx";
    289. int port = 21;
    290. FTPUtil ftp = new FTPUtil();
    291. //上传文件
    292. String absSrcFileName = "C:\tmp\m2eclipse1.zip";
    293. String destDir = "ww/11/22/33";
    294. String destFileName = "m2eclipse1.zip";
    295. ftp.connect(hostname, port, username, password);
    296. ftp.upLoadByFtp(absSrcFileName, destDir, destFileName);
    297. ftp.disconnect();
    298. // 下载文件
    299. String localFileName = "C:\tmp\m2eclipse-download3333.zip";
    300. String remoteFileName = "/ww/11/22/33/m2eclipse.zip";
    301. ftp.connect(hostname, port, username, password);
    302. ftp.downLoadByFtp(remoteFileName, localFileName);
    303. ftp.disconnect();
    304. }
    305. }

    参考链接







  • 相关阅读:
    TestFlight使用方法
    jmeter 单接口测试方案(接口无业务关联)
    jenkins+ANT+jmeter 接口测试环境搭建
    Pytorch实战(3)----分类
    莫烦大大keras的Mnist手写识别(5)----自编码
    莫烦大大keras学习Mnist识别(4)-----RNN
    莫烦大大keras学习Mnist识别(3)-----CNN
    算法68------数组和矩阵问题
    Keras学习基础(2)
    TensorFlow实战笔记(17)---TFlearn
  • 原文地址:https://www.cnblogs.com/ssslinppp/p/6253157.html
Copyright © 2011-2022 走看看