0

I want to upload a existing file from my Android to a FTP-Server.

The following code works, but only in its own project.

public class FtpConnectDemo {
    public static void main(String[] args) {
        uploadDatei(SERVER, "SERVER/htdocs/wa/data/ArtikelDatenbank.csv", "ArtikelDatenbank.csv", USER, PASSWORD);
    }



    public static void uploadDatei(String ftpServer, String pfadUndDateiName, String dateiName, String benutzer, String passwort) {
        StringBuffer sb = new StringBuffer("ftp://");

        sb.append(benutzer);
        sb.append(':');
        sb.append(passwort);
        sb.append('@');
        sb.append(ftpServer);
        sb.append('/');
        sb.append(pfadUndDateiName);
        sb.append(";type=a");

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            URL url = new URL(sb.toString());
            URLConnection urlc = url.openConnection();

            bos = new BufferedOutputStream(urlc.getOutputStream());
            bis = new BufferedInputStream(new FileInputStream(dateiName));

            int i;
            // read byte by byte until end of stream
            while ((i = bis.read()) != -1) {
                bos.write(i);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }
    }
}

If I include this code into my other project it doesn't work anymore. The method is called by a click on a button. The onClickListener should call the second method uploadCsvAufServer()

Here is my other project.

Calling method:

private void initObjekte() {

        dbHelper = new DBController(this);

        this.buttonSync = (Button) this.findViewById(R.id.button_sync);
        this.buttonSync.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // 1. Erstellen einer csv-Datei, die die Werte aus 1. enthält: OK
                Synchronisierung.this.saveUpdateDateiAufSdCard();

                // 2. Kopieren der Datei auf den Webserver
                Synchronisierung.this.uploadCsvAufServer();

                // Bisher als "nein" gekennzeichnete Werte werden als sychronisiert markiert und auf "ja" gesetzt
                Synchronisierung.this.dbHelper.updateSyncStatus();
                Synchronisierung.this.getNichtSyncedDaten();
            }
        });
}

Called method:

public void uploadCsvAufServer() {

    StringBuffer sb = new StringBuffer("ftp://");
    sb.append(this.BENUTZER);
    sb.append(':');
    sb.append(this.PASSWORT);
    sb.append('@');
    sb.append(this.SERVER);
    sb.append('/');
    sb.append(this.SERVER_DATEINAME);
    sb.append(";type=a");

    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        URL url = new URL(sb.toString());
        URLConnection urlc = url.openConnection();

        bos = new BufferedOutputStream(urlc.getOutputStream());
        bis = new BufferedInputStream(new FileInputStream(this.DATEINAME));

        int i;
        // read byte by byte until end of stream
        while ((i = bis.read()) != -1)
        {
            bos.write(i);
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (bis != null) {
            try
            {
                bis.close();
            } catch (IOException ioe)
            {
                ioe.printStackTrace();
            }
        }
        if (bos != null) {
            try
            {
                bos.close();
            } catch (IOException ioe)
            {
                ioe.printStackTrace();
            }
        }
    }
}

Errors from LogCatsee below:

08-22 14:03:15.793: E/AndroidRuntime(773): FATAL EXCEPTION: main
08-22 14:03:15.793: E/AndroidRuntime(773): android.os.NetworkOnMainThreadException
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.net.InetAddress.getByName(InetAddress.java:289)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.net.InetSocketAddress.<init>(InetSocketAddress.java:105)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.net.InetSocketAddress.<init>(InetSocketAddress.java:90)
08-22 14:03:15.793: E/AndroidRuntime(773):  at libcore.net.url.FtpURLConnection.connectInternal(FtpURLConnection.java:219)
08-22 14:03:15.793: E/AndroidRuntime(773):  at libcore.net.url.FtpURLConnection.connect(FtpURLConnection.java:191)
08-22 14:03:15.793: E/AndroidRuntime(773):  at libcore.net.url.FtpURLConnection.getOutputStream(FtpURLConnection.java:339)
08-22 14:03:15.793: E/AndroidRuntime(773):  at de.noretec.nfcsync.view.Synchronisierung.uploadCsvAufServer(Synchronisierung.java:244)
08-22 14:03:15.793: E/AndroidRuntime(773):  at de.noretec.nfcsync.view.Synchronisierung$1.onClick(Synchronisierung.java:95)
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.view.View.performClick(View.java:4204)
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.view.View$PerformClick.run(View.java:17355)
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.os.Handler.handleCallback(Handler.java:725)
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.os.Handler.dispatchMessage(Handler.java:92)
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.os.Looper.loop(Looper.java:137)
08-22 14:03:15.793: E/AndroidRuntime(773):  at android.app.ActivityThread.main(ActivityThread.java:5041)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.lang.reflect.Method.invokeNative(Native Method)
08-22 14:03:15.793: E/AndroidRuntime(773):  at java.lang.reflect.Method.invoke(Method.java:511)
08-22 14:03:15.793: E/AndroidRuntime(773):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
08-22 14:03:15.793: E/AndroidRuntime(773):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
08-22 14:03:15.793: E/AndroidRuntime(773):  at dalvik.system.NativeStart.main(Native Method)
08-22 14:03:19.773: E/Trace(787): error opening trace file: No such file or directory (2)

Does anybody see why I got these errors?

=======

UPDATE:

=======

As you said, it is a problem with android.os.NetworkOnMainThreadException. I can't use the network interface in the main (UI) thread. So I tried a seperate class which is extended from AsyncTask<>. Now my app doesn't crash anymore but throws warnings.

08-22 17:14:24.852: W/System.err(780): java.io.IOException: Unable to connect to server: Unable to retrieve file: 550
08-22 17:14:24.870: W/System.err(780):  at libcore.net.url.FtpURLConnection.connect(FtpURLConnection.java:203)
08-22 17:14:24.870: W/System.err(780):  at libcore.net.url.FtpURLConnection.getOutputStream(FtpURLConnection.java:339)
08-22 17:14:24.870: W/System.err(780):  at de.noretec.nfcsync.controller.FileUpload.doInBackground(FileUpload.java:40)
08-22 17:14:24.870: W/System.err(780):  at de.noretec.nfcsync.controller.FileUpload.doInBackground(FileUpload.java:1)
08-22 17:14:24.878: W/System.err(780):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
08-22 17:14:24.878: W/System.err(780):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
08-22 17:14:24.878: W/System.err(780):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
08-22 17:14:24.878: W/System.err(780):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
08-22 17:14:24.878: W/System.err(780):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
08-22 17:14:24.878: W/System.err(780):  at java.lang.Thread.run(Thread.java:856)
08-22 17:14:26.148: W/System.err(780): java.io.IOException: Unable to connect to server: Unable to retrieve file: 550
08-22 17:14:26.148: W/System.err(780):  at libcore.net.url.FtpURLConnection.connect(FtpURLConnection.java:203)
08-22 17:14:26.148: W/System.err(780):  at libcore.net.url.FtpURLConnection.getOutputStream(FtpURLConnection.java:339)
08-22 17:14:26.148: W/System.err(780):  at de.noretec.nfcsync.controller.FileUpload.doInBackground(FileUpload.java:40)
08-22 17:14:26.148: W/System.err(780):  at de.noretec.nfcsync.controller.FileUpload.doInBackground(FileUpload.java:1)
08-22 17:14:26.148: W/System.err(780):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
08-22 17:14:26.148: W/System.err(780):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
08-22 17:14:26.148: W/System.err(780):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
08-22 17:14:26.148: W/System.err(780):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
08-22 17:14:26.148: W/System.err(780):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
08-22 17:14:26.148: W/System.err(780):  at java.lang.Thread.run(Thread.java:856)

To do a async thread I think I have to use the protected Void doInBackground(String... arg0) method.

Here is my actual code. I'm not sure if I used the right form for the class head: public class FileUpload extends AsyncTask I don't have any parameters but I could use one.

    public class FileUpload extends AsyncTask<String, Void, Void> {

    @Override
    protected Void doInBackground(String... arg0) {
        Server server = new Server();
        StringBuffer sb = new StringBuffer("ftp://");

        sb.append(server.getBenutzer());
        sb.append(':');
        sb.append(server.getPasswort());
        sb.append('@');
        sb.append(server.getFtpServer());
        sb.append('/');
        sb.append(server.getPfadUndDateiName());
        sb.append(";type=a");

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            URL url = new URL(sb.toString());
            URLConnection urlc = url.openConnection();

            bos = new BufferedOutputStream(urlc.getOutputStream());
            bis = new BufferedInputStream(new FileInputStream(server.getDateiName()));

            int i;
            // read byte by byte until end of stream
            while ((i = bis.read()) != -1)
            {
                bos.write(i);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try
                {
                    bis.close();
                } catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
            if (bos != null) {
                try
                {
                    bos.close();
                } catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
        }
        return null;
    }



    protected void onProgressUpdate(Integer... progress) {

    }



    protected void onPostExecute(Long result) {

    }
}

=========

SOLVED

=========

I used an seperate class extended from AsyncTask.

I call it with:

new FTPFileUpload().execute(                    
    server.getFtpServer(),
    server.getBenutzer(),
    server.getPasswort(),
    Synchronisierung.this.notSyncedContent.toString(),
    server.getPfadUndDateiName());

Using:

public class FTPFileUpload extends AsyncTask<String, Void, Void> {

    @Override
    protected Void doInBackground(String... params) {
        FTPClient con = new FTPClient();
        try {

            con.connect(InetAddress.getByName(params[0]));

            if (con.login(params[1], params[2])) {
                con.enterLocalPassiveMode();
                String data = params[3];
                ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes());
                boolean result = con.storeFile(params[4], in);
                in.close();
                // if (result)
                // System.out.println("upload result: " + result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            con.logout();
            con.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}
squietschi
  • 71
  • 1
  • 7

2 Answers2

1

Try using Apache commons net ftp library.

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

public class FTPUploader {

    FTPClient ftp = null;

    public FTPUploader(String host, String user, String pwd) throws Exception{
        ftp = new FTPClient();
        ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
        int reply;
        ftp.connect(host);
        reply = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            throw new Exception("Exception in connecting to FTP Server");
        }
        ftp.login(user, pwd);
        ftp.setFileType(FTP.BINARY_FILE_TYPE);
        ftp.enterLocalPassiveMode();
    }
    public void uploadFile(String localFileFullName, String fileName, String hostDir)
            throws Exception {
        try(InputStream input = new FileInputStream(new File(localFileFullName))){
        this.ftp.storeFile(hostDir + fileName, input);
        }
    }

    public void disconnect(){
        if (this.ftp.isConnected()) {
            try {
                this.ftp.logout();
                this.ftp.disconnect();
            } catch (IOException f) {
                // do nothing as file is already saved to server
            }
        }
    }

Update:

Try using your code from Thread or service because on android versions greater than gingerbread the os does not allow you to do allow you to Networking on the Ui Main thread so this Exception has occured

 android.os.NetworkOnMainThreadException

to read further go to this site.

Update:

try changing this line

sb.append(";type=a");

to

sb.append(";type=i");
Prakhar
  • 2,270
  • 19
  • 26
  • I tried using the AsyncTask. But there are other warnings see below my UPDATE. I am not sure if I used the right syntax method head of doInBackground(). I do not have any parameter, but I could give one. – squietschi Aug 23 '13 at 11:09
  • I changed the type from a to i. No alteration. – squietschi Aug 23 '13 at 14:01
  • I used your class but when uploading a file, I am getting the file wit size ZERO. What am I making wring? – Meir May 09 '16 at 06:58
0

08-22 14:03:15.793: E/AndroidRuntime(773): FATAL EXCEPTION: main 08-22 14:03:15.793: E/AndroidRuntime(773): android.os.NetworkOnMainThreadException

the problem is here from 2.x + android versions you cant do network operations the the main UI thread because you block it. You should use AsynTask its very good for this kind of operations. Or you make a FileTransferThread class.

cesztoszule
  • 286
  • 3
  • 12
  • I tried using the AsyncTask. But there are other warnings see below my UPDATE. I am not sure if I used the right syntax method head of doInBackground(). I do not have any parameter, but I could give one. – squietschi Aug 23 '13 at 11:12