I'm using Apache commonsnet library for FTP. I'm able to create the folders in FTP server. But whenever I storeFile it's failing and returning me 550 error.
FTPUpload
private boolean ftpUpload(String remoteFilePath) {
FTPSClient ftpsClient = null;
try {
ftpsClient = new FTPSClient("SSL", true);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
FileInputStream fis;
boolean result = false;
try {
if (ftpsClient != null) {
ftpsClient.setConnectTimeout(10000);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(null, null);
KeyManager km = kmf.getKeyManagers()[0];
ftpsClient.setKeyManager(km);
ftpsClient.connect(InetAddress.getByName(getString(R.string.ftp_hostname)), 990);
boolean isLoggedIn = ftpsClient.login(getString(R.string.ftp_username), getString(R.string.ftp_password));
if (isLoggedIn) {
// On Successful login
ftpsClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpsClient.enterLocalPassiveMode();
ftpsClient.setBufferSize(1000);
// Check remotePath exists else create folders
int index = remoteFilePath.lastIndexOf("/");
String remoteDir = null;
if (index != -1)
remoteDir = remoteFilePath.substring(0, index);
if (remoteDir != null)
/**
* changeWorkingDirectory returns whether the specified directory exist or not.
* If not exist in remote, create folders
*/
if (!ftpsClient.changeWorkingDirectory(remoteDir)) {
if (makeDirectories(ftpsClient, remoteDir))
ftpsClient.changeWorkingDirectory(remoteFilePath);
else
Log.e(this.getClass().getSimpleName(), "remote path is not available");
} else
ftpsClient.changeWorkingDirectory(remoteFilePath);
//Testing
File localFilePath = new File(Environment.getExternalStorageDirectory() + "/qwerty.png");
ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
try{
int reply = ftpsClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpsClient.disconnect();
Log.e(this.getClass().getSimpleName(), "Connection Refused by server");
return false;
}
} catch(Exception e) {
e.printStackTrace();
}
// Get the stream of the file
String testName = localFilePath.getName();
fis = new FileInputStream(localFilePath);
// Upload file to the ftp server
result = ftpsClient.storeFile(testName, fis);
fis.close();
Log.i(this.getClass().getSimpleName(), "FTP Store Result " + result);
if (result) {
result = true;
} else {
result = false;
}
} else {
Log.e(this.getClass().getSimpleName(), "Login Fail!");
result = false;
}
// logout from ftp server
ftpsClient.logout();
}
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(), "FTP Exception!");
result = false;
}
return result;
}
It's connecting, authenticating, created new folder but storingFile/getReplyCode always returns 550. What is wrong here? I have removed KeyManagerFactory also but no luck.
Related
There is a python server in my pepper robot and it works fine on the machine. I use putty to start the server and ncat to send my command and there is no problem at all.
In my Connection fragment I need to create a channel to send an ssh command to robot to start the server and then I need to create socket to the server. Then when I send a package to connect server to the application with this command: {'command': '< SYS_CONNECT>'}
In response server should send some information about robot like name, battery level and etc. BUT i just got null from server.
There is application used to run in anroid 5.1 and some years before. Now I deceided to create new application and import some class and components from old application.
private boolean connect(){
state = ConnectionState.CONNECTION_INIT;
for( String h : hostAdresses ){
try{
host = h;
// create socket
socket = new Socket( InetAddress.getByName(host).getHostAddress(), port );
socket.setSoTimeout(defaultReadTimeout);
in = new BufferedReader( new InputStreamReader( new BufferedInputStream(socket.getInputStream()) ) );
out = socket.getOutputStream();
// try to connect
int tries = connectionMaxTries;
while(!stop && socket != null && state == ConnectionState.CONNECTION_INIT && tries > 0) {
// send connection request
DataRequestPackage p = new DataRequestPackage(
PepperCommands.SYS_CONNECT,
new String[0]);
String data = gson.toJson(p);
// wait for data
//data = in.readLine();
try {
out.write(data.getBytes());
Log.w(TAG, "Sending data =" + data);
StringBuilder sb = new StringBuilder();
while ((data = in.readLine()) != null) {
sb.append(data);
Log.d(TAG, "loop data");
}
data = sb.toString();
} catch (Exception e) {
Log.d(TAG, "error on reading data");
}
Log.w(TAG, "Receiving data = " + data);
Log.w(TAG, "in.readLine(), data = " + in.readLine());
DataResponsePackage response = gson.fromJson(data, DataResponsePackage.class);
if( response.request.command == PepperCommands.SYS_CONNECT
&& response.requestSuccessfull){
state = ConnectionState.CONNECTION_ESTABLISHED;
notifyDataRecievedListeners(response);
return true;
}
tries--;
}
}catch(UnknownHostException e){
state = ConnectionState.CONNECTION_UNKNOWN_HOST;
Log.w(TAG, "Host unknown " + host);
MainActivity.getInstance().runOnUiThread( new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.getInstance().getApplicationContext(),
R.string.net_unknown_host, Toast.LENGTH_SHORT).show();
}
});
} catch (IOException e) {
state = ConnectionState.CONNECTION_ESTABLISHED_FAILED;
Log.w(TAG, "IO Exception on connnection with " + host + ":" + port);
}
}
return false;
}
Tries to start remote server using ssh.
/**
* Tries to start remote server using ssh.
* #return {#code true} if server started, {#code false} otherwise.
*/
private boolean sshServerStart(){
// show message
MainActivity.getInstance().runOnUiThread( new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.getInstance().getApplicationContext(),
R.string.net_try_server_start, Toast.LENGTH_SHORT).show();
}
});
// send command
String[] vCommands = new String[]{ SSH_COMMAND_SERVER_START };
if( sendSSHCommands( vCommands ).size() > 0 ){
// wait a few seconds for server to start
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
return true;
}
return false;
}
Connecting to ssh server
/**
* Connecting to ssh server
* #return {#code true} if successful connected, {#code false} otherwise.
*/
private Session connectSSH(){
for( String host : hostAdresses ){
try {
// get user information
SharedPreferences vPreferences = MainActivity.getPreferences();
String vUser = vPreferences.getString(PREFERENCES_SSH_USER, "nao");
String vPassword = vPreferences.getString(PREFERENCES_SSH_PASSWORD, "nao");
if( mUseCustomLoginData ){
vUser = mSSHUser;
vPassword = mSSHPassword;
}
// create session
Session vSession = mSSH.getSession(vUser,
InetAddress.getByName(host).getHostAddress().toString(),
22 );
vSession.setPassword( vPassword );
// avoid asking for key auth
Properties vProperties = new Properties();
vProperties.put("StrictHostKeyChecking", "no");
vSession.setConfig(vProperties);
try{
// connect to ssh server
vSession.connect();
} catch( JSchException err ){
if( err.getMessage().contains("Auth fail") ){
// ask for custom login data
if( askForCustomLoginData() ){
vSession = connectSSH();
} else {
return null;
}
} else {
System.out.println("EXCEPTION: " + err.getMessage());
err.printStackTrace();
}
}
return vSession;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (JSchException e) {
e.printStackTrace();
}
}
return null;
}
I expect on this code response.request.command return SYS_CONNECT and response.requestSuccessfull return true on this line but I got unexpected null response
if( response.request.command == PepperCommands.SYS_CONNECT && response.requestSuccessfull){
I am connected to a Server whose address is 192.168.1.254 and on typing this address in the browser it is showing the list of available folder
i want to display the name of the folder in my android application i have tried the following code but no-luck.
try {
SmbFile test = new SmbFile("smb://192.168.1.254");
SmbFile[] files = test.listFiles();
if (files != null)
for (SmbFile s : files) {
Log.d("debug", s.getName());
}
} catch (SmbException e) {
Log.d("debug", "ERROR");
} catch (Exception e) {
Log.d("debug", "ERROR");
}
which i find here
and i also tried
File f = new File("//192.168.1.254");
//also tried with File f = new File("http//192.168.1.254");
File[] files = f.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
// Specify the extentions of files to be included.
return name.endsWith(".bmp") || name.endsWith(".gif");
}
});
// get names of the files
String[] fileNamesArray = null;
for (int indx = 0; indx < files.length(); indx++) {
Log.d("name",files[indx].getName());
}
return fileNamesArray;
Seems you need FTP client for list files on remote location. Try to use, for example, ftp4j library as described in it's official documentation or this Android Example by devert. Exactly list files on remote FTP server with ftp4j by Arun you can find here:
FTPClient client = null;
try { // Get the FTP Connection from the
Utility class client =FTPUtility.connect(ipAddress, userName,
password);
if (client != null) { /* List all file inside the directory */
FTPFile[] fileArray = client.list();
System.out.println("List of files...");
for (int i = 0; i < fileArray.length; i++) {
FTPFile file = fileArray[i];
if (file != null) {
if (file.TYPE_FILE == FTPFile.TYPE_FILE) // File {
System.out.println("File Name = " + file.getName() + " ; File Size = " + file.getSize() + " ;Modified Date = " + file.getModifiedDate());
} else if (file.TYPE_DIRECTORY == FTPFile.TYPE_DIRECTORY) // Directory
{
System.out.println("Directory Name = " + file.getName() + " ; Directory Size = " + file.getSize() + " ;Modified Date = " + file.getModifiedDate());
} else if (file.TYPE_LINK == FTPFile.TYPE_LINK) // Link
{
System.out.println("Link Name = " + file.getName() + " ;Modified Date = "
+ file.getModifiedDate());
}
}
}
}
} catch(
Exception e)
{
System.err.println("ERROR : Error in Connecting to Remote Machine... Hence exitting..."); //
e.printStackTrace();
System.exit(2);
}
finally
{
try {
client.disconnect(true);
} catch
(Exception e) {
}
}
Update
If "there is no active port for ftp , and my current finding is device is having only 4 active port i.e 80,443,3333,8192" seems file list send over HTTP and you can download it via HttpURLConnection and parse response. Something like this:
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL("http://192.168.1.254");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
int responseCode = connection.getResponseCode();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder responseStringBuilder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
responseStringBuilder .append(line);
responseStringBuilder .append("\n");
}
// Parse responseStringBuilder.toString() (probably as HTML) here:
...
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
One way is to download html as a string from the server. Then use
urlConnection = new URL("your_url").openConnection();
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
while ((String line = reader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
String your_data = Html.fromHtml(stringBuilder.toString());
This will contain the table in text format. You can process it to get the required data.
I am facing trouble in updating the existing cached file within my Android Application.
for(DbxFileInfo fInfo : fileList)
{
Log.d(TAG, "File Path = "+fInfo.path.toString());
String fileName = fInfo.path.getName().trim();
try
{
DbxPath tempFilePath = new DbxPath(fInfo.path.toString());
DbxFile tempFile = mDbFileSystem.open(tempFilePath);
if(tempFile.getSyncStatus().isCached)
{
Log.v(TAG, "File is already cached !");
if(tempFile.getSyncStatus().isLatest)
{
Log.v(TAG, "File's Latest Version is Cached !");
}
else
{
Log.v(TAG, "File's Latest Version is not Cached !");
}
}
try
{
tempFile.getNewerStatus();
}
catch(Exception dBException)
{
Log.e(TAG, "Error while getting newer Status !");
}
InputStream input = new BufferedInputStream(tempFile.getReadStream());
OutputStream output = new FileOutputStream(cntx.getFilesDir() + "/SyncedData/" + fileName);
byte data[] = new byte[1024];
int count;
//total size is in Bytes
while ((count = input.read(data)) != -1)
{
totalBytesDownloaded += count;
publishProgress((int) (totalBytesDownloaded * 100/totalFileSize));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
tempFile.close();
mDbFileSystem.delete(tempFile.getPath());
result = true;
}
catch(Exception e)
{
Log.e(TAG, "Error occured while downloading files !, Error = "+e.toString());
result = false;
}
}
I am putting different files with same names on my Synced Dropbox folder and after Downloading them i am getting the older version of files.
Is there any way i can update my existing cached files or Clear the Dropbox Cache (that is within my App)
Any help is highly appreciated, thanks.
Here's how the Sync API works:
It constantly syncs metadata (what files exist and their revisions) and notifies you via listeners you set up on the file system.
For open files, it downloads any newer version of the file available and notifies you via the listener you set up on the file itself.
So if you want to get the latest version of a file, you need to open the file and hold it open while waiting for the listener to notify you that the newer version of the file is cached. Then you can call update to get access to that new data.
EDIT: Pasting code from https://www.dropbox.com/developers/sync/start/android#listeners:
DbxFileStatus status = testFile.getSyncStatus();
if (!status.isCached) {
testFile.addListener(new DbxFile.Listener() {
#Override
public void onFileChange(DbxFile file) {
// Check testFile.getSyncStatus() and read if it's ready
}
});
// Check if testFile.getSyncStatus() is ready already to ensure nothing
// was missed while adding the listener
}
Here is my attempt to get the latest file but as I stated in the comment to your question, it seems I sometimes have to do two sync calls in order to get the latest file.
The fileModified and fileSize comparison is rather crude but seems to do the trick. Better than what I have found so far at least.
public DropboxFileDownloader() {
super("FileDownloader");
}
#Override
protected void onHandleIntent(Intent intent) {
String turiosHome = intent.getStringExtra(Constants.EXTRA_HOME);
String fileName = intent.getStringExtra(Constants.EXTRA_FILENAME);
String folderPath = intent.getStringExtra(Constants.EXTRA_FOLDERPATH);
ResultReceiver receiver = intent.getParcelableExtra(Constants.EXTRA_RECEIVER);
Bundle bundle = new Bundle();
String fullpath = folderPath + "/" + fileName;
DbxFile file;
long fileModified = 0;
long fileSize = 0;
try {
file = dbxFs.open(new DbxPath(fullpath));
try {
DbxFileStatus fileStatus = file.getNewerStatus();
if (fileStatus != null && !fileStatus.isLatest) {
/*while (file.getNewerStatus().pending == PendingOperation.DOWNLOAD) {
Log.d(TAG, "Waiting for " + fileName + " to be downloaded");
Thread.sleep(1000);
}*/
if (fileStatus.isCached) {
//Start of Edit
try
{
//Running this do while loop until the Latest version of this file is cached.
do
{
Log.d(TAG, "Updating the existing file !");
//Updating the file
file.update();
while (file.getNewerStatus().pending ==PendingOperation.DOWNLOAD)
{
Log.d(TAG, "Waiting for " + fileName+ " to be downloaded");
Thread.sleep(1000);
}
} while (fileStatus.isLatest);
}
catch (Exception dBException)
{
Log.e(TAG, "Error while getting newer Status !, Error = "+dBException.toString());
dBException.printStackTrace();
}
//End of Edit
}
}
fileModified = file.getInfo().modifiedTime.getTime();
fileSize = file.getInfo().size;
} catch (DbxException e) {
Log.e(TAG, e.getMessage(), e);
bundle.putString(Constants.EXTRA_MESSAGE, e.getMessage());
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_ERROR, bundle);
return;
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (InvalidPathException e1) {
Log.e(TAG, e1.getMessage(), e1);
bundle.putString(Constants.EXTRA_MESSAGE, e1.getMessage());
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_ERROR, bundle);
return;
} catch (DbxException e1) {
Log.e(TAG, e1.getMessage(), e1);
bundle.putString(Constants.EXTRA_MESSAGE, e1.getMessage());
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_ERROR, bundle);
return;
}
File stored_dir = new File(turiosHome + "/" + folderPath);
if (!stored_dir.exists()) {
stored_dir.mkdirs();
}
File stored_file = new File(turiosHome + "/" + folderPath,
fileName);
// File stored_file = getFileStreamPath(fileName);
long local_modified = stored_file.lastModified();
long local_size = stored_file.length();
boolean should_sync = (fileModified > local_modified)
|| fileSize != local_size;// && Math.abs(fileModified -
// local_modified) >
// TimeUnit.MILLISECONDS.convert(1,
// TimeUnit.MINUTES);
boolean fileexists = stored_file.exists();
if (should_sync || !fileexists) {
InputStream inputStream = null;
FileOutputStream out = null;
try {
// read this file into InputStream
inputStream = file.getReadStream();
out = new FileOutputStream(stored_file);
int read = 0;
byte[] bytes = new byte[1024];
int bytes_counter = 0;
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
bytes_counter++;
}
Log.d(TAG, "Wrote: " + file.getPath().getName() + " "
+ bytes_counter + " kb");
if (!fileexists) {
bundle.putString(Constants.EXTRA_FILEPATH, fullpath);
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_CREATED, bundle);
} else {
bundle.putString(Constants.EXTRA_FILEPATH, fullpath);
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_UPDATED, bundle);
}
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
bundle.putString(Constants.EXTRA_MESSAGE, e.getMessage());
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_ERROR, bundle);
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (out != null) {
out.flush();
out.close();
}
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
bundle.putString(Constants.EXTRA_MESSAGE, e.getMessage());
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_ERROR, bundle);
}
}
}
else {
bundle.putString(Constants.EXTRA_FILEPATH, fullpath);
receiver.send(DropboxFileDownloaderResultReceiver.RESULTCODE_UPTODATE, bundle);
}
file.close();
}
}
I can't found working example for me. But for my case - i don't need cashed version of files - only newest (data synchronization between devices).
I used
mDbFileSystem.setMaxFileCacheSize(0);
All or nothing. But now nessasary thread for downloading in background.
i am using org.apache.commons.net.ftp library, i have uploaded the file but when i try to download the file from FTP Server to my emulator's virtual SDCard it didn't work.
how to specify the destination path? that is the SD Card path where i need to download, and how to specify the source file path ( file in FTP server page path)?
here is the code i tried to perform the download,
try
{
FileOutputStream desFileStream1 = new FileOutputStream("/sdcard/Baby.jpg");
Boolean status1 = con.retrieveFile("/Baby", desFileStream1);
if(status1)
{
lblResult2.setText("File downloaded Successfully");
}
else
{
lblResult2.setText("File download failed");
}
DesFileStream1.close();
} catch (Exception e)
{
Log.d(TAG, "download failed");
}
any one of you help me out.
Use getExternalStorageDirectory() or getExternalStoragePublicDirectory() on Environment to find the proper root of external storage, which is not /sdcard on most Android devices.
File file = new File(Environment.getExternalStorageDirectory() + "/pdf");
if(!file.exists())
file.mkdir(); //directory is created;
try {
ftp = new FTPClient();
ftp.connect("yours ftp URL",21);//don't write ftp://
try {
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
throw new Exception("Connect failed: " + ftp.getReplyString());
}
if (!ftp.login("username","password")) {
throw new Exception("Login failed: " + ftp.getReplyString());
}
try {
ftp.enterLocalPassiveMode();
if (!ftp.setFileType(FTP.BINARY_FILE_TYPE)) {
// Log.e(TAG, "Setting binary file type failed.");
}
transferFile(ftp);
} catch(Exception e) {
// handleThrowable(e);
} finally {
if (!ftp.logout()) {
// Log.e(TAG, "Logout failed.");
}
}
} catch(Exception e) {
// handleThrowable(e);
} finally {
ftp.disconnect();
}
} catch(Exception e) {
// handleThrowable(e);
}
}
private void transferFile(FTPClient ftp) throws Exception {
long fileSize=0;
fileSize = getFileSize(ftp, "nag.pdf");
Log.v("async","fileSize"+fileSize);
if(!(fileSize==0)){
InputStream is = retrieveFileStream(ftp, "nag.pdf");
downloadFile(is, fileSize);
is.close();
}
else
//nosuch files
if (!ftp.completePendingCommand()) {
throw new Exception("Pending command failed: " + ftp.getReplyString());
}
}
private InputStream retrieveFileStream(FTPClient ftp, String filePath)
throws Exception {
InputStream is = ftp.retrieveFileStream(filePath);
int reply = ftp.getReplyCode();
if (is == null
|| (!FTPReply.isPositivePreliminary(reply)
&& !FTPReply.isPositiveCompletion(reply))) {
throw new Exception(ftp.getReplyString());
}
return is;
}
private byte[] downloadFile(InputStream is, long fileSize)
throws Exception {
outputStream os = newFileOutputStream(Environment.getExternalStorageDirectory()
+ "/pdf/nag.pdf");
byte[] buffer = new byte[(int) fileSize];
int readCount;
while( (readCount = is.read(buffer)) > 0) {
os.write(buffer, 0, readCount);
}
Log.i("tag", "buffer = " + buffer);
return buffer; // <-- Here is your file's contents !!!
}
private long getFileSize(FTPClient ftp, String filePath) throws Exception {
long fileSize = 0;
FTPFile[] files = ftp.listFiles(filePath);
if (files.length == 1 && files[0].isFile()) {
fileSize = files[0].getSize();
}
Log.i("tag", "File size = " + fileSize);
return fileSize;
}
}
I am a newbie to Android. I am trying download a file from ftp server to sdcard using Apache Commons FTPClient. The line InputStream input = client.retrieveFileStream("/" + fileName); always returns null. But the file is there in Ftp location. Kindly help me to know where the mistake is.
I have set the following permissions in my manifest; android:name="android.permission.INTERNET" and android:name="android.permission.WRITE_EXTERNAL_STORAGE"
My Code
private static void downLoad(){
FTPClient client = new FTPClient();
FileOutputStream fos = null;
try {
client.connect("ftp.doamin.com");
client.login("8888", "8888");
String filePath = "/mnt/sdcard/download/CheckboxHTML.txt" ;
String fileName = "CheckboxHTML.txt";
fos = new FileOutputStream(filePath);
InputStream input = client.retrieveFileStream("/" + fileName);
byte[] data = new byte[1024];
int count = input.read(data);
while ((count = input.read(data)) != -1) {
fos.write(data, 0, count);
}
fos.close();
if(!client.completePendingCommand()) {
client.logout();
client.disconnect();
System.err.println("File transfer failed.");
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Thanks for your time and interest. Ananth.
AFAIK. You are suppose to finalize file transfers by calling completePendingCommand() and verifying that the transfer was indeed successful. i.e. you need to add call the function below fos.clos().
fos.close();
client.completePendingCommand()
You may also consider this, according to the API for FTPClient.retrieveFileStream(), the method returns null when it cannot open the data connection, in which case you should check the reply code (e.g. getReplyCode(), getReplyString(), getReplyStrings()) to see why it failed.
File file = new File(Environment.getExternalStorageDirectory() + "/pdf");
if(!file.exists())
file.mkdir(); //directory is created;
try {
ftp = new FTPClient();
ftp.connect("yours ftp URL",21);//don't write ftp://
try {
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
throw new Exception("Connect failed: " + ftp.getReplyString());
}
if (!ftp.login("username","password")) {
throw new Exception("Login failed: " + ftp.getReplyString());
}
try {
ftp.enterLocalPassiveMode();
if (!ftp.setFileType(FTP.BINARY_FILE_TYPE)) {
// Log.e(TAG, "Setting binary file type failed.");
}
transferFile(ftp);
} catch(Exception e) {
// handleThrowable(e);
} finally {
if (!ftp.logout()) {
// Log.e(TAG, "Logout failed.");
}
}
} catch(Exception e) {
// handleThrowable(e);
} finally {
ftp.disconnect();
}
} catch(Exception e) {
// handleThrowable(e);
}
}
private void transferFile(FTPClient ftp) throws Exception {
long fileSize=0;
fileSize = getFileSize(ftp, "nag.pdf");
Log.v("async","fileSize"+fileSize);
if(!(fileSize==0)){
InputStream is = retrieveFileStream(ftp, "nag.pdf");
downloadFile(is, fileSize);
is.close();
}
else
//nosuch files
if (!ftp.completePendingCommand()) {
throw new Exception("Pending command failed: " + ftp.getReplyString());
}
}
private InputStream retrieveFileStream(FTPClient ftp, String filePath)
throws Exception {
InputStream is = ftp.retrieveFileStream(filePath);
int reply = ftp.getReplyCode();
if (is == null
|| (!FTPReply.isPositivePreliminary(reply)
&& !FTPReply.isPositiveCompletion(reply))) {
throw new Exception(ftp.getReplyString());
}
return is;
}
private byte[] downloadFile(InputStream is, long fileSize)
throws Exception {
outputStream os = newFileOutputStream(Environment.getExternalStorageDirectory()
+ "/pdf/nag.pdf");
byte[] buffer = new byte[(int) fileSize];
int readCount;
while( (readCount = is.read(buffer)) > 0) {
os.write(buffer, 0, readCount);
}
Log.i("tag", "buffer = " + buffer);
return buffer; // <-- Here is your file's contents !!!
}
private long getFileSize(FTPClient ftp, String filePath) throws Exception {
long fileSize = 0;
FTPFile[] files = ftp.listFiles(filePath);
if (files.length == 1 && files[0].isFile()) {
fileSize = files[0].getSize();
}
Log.i("tag", "File size = " + fileSize);
return fileSize;
}
}
After have worked on this problem and spent hours, I've found out that the Android Apache retrieveFile() and retrieveFileStream sometimes don't work very well when the FileSize is too big.
Ensure to set the right TypeFile to BinaryFile
mFTPClient.setFileType(FTP.BINARY_FILE_TYPE);
Also never forget to pass in LocalPassiveMode for download commands
mFTPClient.enterLocalPassiveMode();