主Activity: FTPMainActivity
- <span style="font-size:14px; color:#000000">package com.example.ftpdemo;
- import android.os.Bundle;
- import android.os.StrictMode;
- import android.app.Activity;
- import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- /**
- * 2013年09月20日21:28:51 测试demo
- *
- * 1.文件上传到FTP服务器
- * 2.从FTP服务器上下载文件
- *
- * 所需jar包:commons-net-3.0.1.jar
- * 将commons-net-3.0.1.jar放于libs中
- *
- * @author xiaoyaomeng
- *
- */
- public class FTPMainActivity extends Activity implements OnClickListener {
- //傻逼Buttons
- private Button buttonUpLoad = null;
- private Button buttonDownLoad = null;
- //FTP工具类
- private FTPUtils ftpUtils = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_ftpmain);
- //获取控件对象
- buttonUpLoad = (Button) findViewById(R.id.button_upload);
- buttonDownLoad = (Button) findViewById(R.id.button_download);
- //设置控件对应相应函数
- buttonUpLoad.setOnClickListener(this);
- buttonDownLoad.setOnClickListener(this);
- if (android.os.Build.VERSION.SDK_INT > 9) {
- StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
- StrictMode.setThreadPolicy(policy);
- }
- //初始化和FTP服务器交互的类
- InitFTPServerSetting();
- }
- public void InitFTPServerSetting() {
- // TODO Auto-generated method stub
- ftpUtils = FTPUtils.getInstance();
- boolean flag = ftpUtils.initFTPSetting("chenww.3vfree.us", 21, "chenww", "chenww");
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.ftpmain, menu);
- return true;
- }
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- switch (v.getId()) {
- case R.id.button_upload: {
- //上传文件
- }
- break;
- case R.id.button_download: {
- //下载文件
- }
- break;
- default:
- break;
- }
- }
- }</span>
工具类:FTPUtils
- <strong><span style="font-size:14px">package com.example.ftpdemo;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.net.SocketException;
- import org.apache.commons.net.ftp.FTP;
- import org.apache.commons.net.ftp.FTPClient;
- import org.apache.commons.net.ftp.FTPFile;
- import org.apache.commons.net.ftp.FTPReply;
- import android.R.bool;
- /**
- * 2013年09月20日21:38:04
- *
- * 用于Android和FTP服务器进行交互的工具类
- *
- * @author xiaoyaomeng
- *
- */
- public class FTPUtils {
- private FTPClient ftpClient = null;
- private static FTPUtils ftpUtilsInstance = null;
- private String FTPUrl;
- private int FTPPort;
- private String UserName;
- private String UserPassword;
- private FTPUtils()
- {
- ftpClient = new FTPClient();
- }
- /*
- * 得到类对象实例(因为只能有一个这样的类对象,所以用单例模式)
- */
- public static FTPUtils getInstance() {
- if (ftpUtilsInstance == null)
- {
- ftpUtilsInstance = new FTPUtils();
- }
- return ftpUtilsInstance;
- }
- /**
- * 设置FTP服务器
- * @param FTPUrl FTP服务器ip地址
- * @param FTPPort FTP服务器端口号
- * @param UserName 登陆FTP服务器的账号
- * @param UserPassword 登陆FTP服务器的密码
- * @return
- */
- public boolean initFTPSetting(String FTPUrl, int FTPPort, String UserName, String UserPassword)
- {
- this.FTPUrl = FTPUrl;
- this.FTPPort = FTPPort;
- this.UserName = UserName;
- this.UserPassword = UserPassword;
- int reply;
- try {
- //1.要连接的FTP服务器Url,Port
- ftpClient.connect(FTPUrl, FTPPort);
- //2.登陆FTP服务器
- ftpClient.login(UserName, UserPassword);
- //3.看返回的值是不是230,如果是,表示登陆成功
- reply = ftpClient.getReplyCode();
- if (!FTPReply.isPositiveCompletion(reply))
- {
- //断开
- ftpClient.disconnect();
- return false;
- }
- return true;
- } catch (SocketException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return false;
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 上传文件
- * @param FilePath 要上传文件所在SDCard的路径
- * @param FileName 要上传的文件的文件名(如:Sim唯一标识码)
- * @return true为成功,false为失败
- */
- public boolean uploadFile(String FilePath, String FileName) {
- if (!ftpClient.isConnected())
- {
- if (!initFTPSetting(FTPUrl, FTPPort, UserName, UserPassword))
- {
- return false;
- }
- }
- try {
- //设置存储路径
- ftpClient.makeDirectory("/data");
- ftpClient.changeWorkingDirectory("/data");
- //设置上传文件需要的一些基本信息
- ftpClient.setBufferSize(1024);
- ftpClient.setControlEncoding("UTF-8");
- ftpClient.enterLocalPassiveMode();
- ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
- //文件上传吧~
- FileInputStream fileInputStream = new FileInputStream(FilePath);
- ftpClient.storeFile(FileName, fileInputStream);
- //关闭文件流
- fileInputStream.close();
- //退出登陆FTP,关闭ftpCLient的连接
- ftpClient.logout();
- ftpClient.disconnect();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return false;
- }
- return true;
- }
- /**
- * 下载文件
- * @param FilePath 要存放的文件的路径
- * @param FileName 远程FTP服务器上的那个文件的名字
- * @return true为成功,false为失败
- */
- public boolean downLoadFile(String FilePath, String FileName) {
- if (!ftpClient.isConnected())
- {
- if (!initFTPSetting(FTPUrl, FTPPort, UserName, UserPassword))
- {
- return false;
- }
- }
- try {
- // 转到指定下载目录
- ftpClient.changeWorkingDirectory("/data");
- // 列出该目录下所有文件
- FTPFile[] files = ftpClient.listFiles();
- // 遍历所有文件,找到指定的文件
- for (FTPFile file : files) {
- if (file.getName().equals(FileName)) {
- //根据绝对路径初始化文件
- File localFile = new File(FilePath);
- // 输出流
- OutputStream outputStream = new FileOutputStream(localFile);
- // 下载文件
- ftpClient.retrieveFile(file.getName(), outputStream);
- //关闭流
- outputStream.close();
- }
- }
- //退出登陆FTP,关闭ftpCLient的连接
- ftpClient.logout();
- ftpClient.disconnect();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return true;
- }
- }</span></strong>
Java使用FTP上传文件被损坏的问题
原因
首先,此问题是因为FTP协议定义的数据传输方式有关,当Java FTP客户端使用ASCII传输时会发现有些上传的文件已经被损坏。
FTP协议规定了两种传输方式分别是ASCII与binary方式:
-
ASCII 方式,这种机制指,在针对传输内容是 ASCII 码文本时,文件内容会被调整,有时会造成传输的文件被损坏, ASCII 方式会把文件中的某些字符串位丢弃,所以不能保证文件数据的每一位都是重要的。
-
二进制方式,首先二进制方式保证了文件内容所有数据位都是重要的。
-
经过验证在传输文件类型为非文本内容的文件,使用 ASCII 传输方式造成 copy 的文件已经损坏。
示例代码(注意FTP.BINARY_FILE_TYPE/FTP.ASCII_FILE_TYPE):
- /**
- * 向远程服务器上传资源
- * @param destResource 上传文件对象
- * @return {true:成功;false:失败}
- * @throws IOException IOException
- */
- public boolean uploadFile(File destResource) throws IOException {
- InputStream ins = (new FileInputStream(destResource));
- ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
- // ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
- ftpClient.changeWorkingDirectory("tmp");
- boolean rtnFlag = ftpClient.storeFile(destResource.getName(), ins);
- ins.close();
- return rtnFlag;
- }