ftpclient-cpp icon indicating copy to clipboard operation
ftpclient-cpp copied to clipboard

Upload file to FTP server (Ubuntu)

Open victoriastraberg opened this issue 2 years ago • 9 comments
trafficstars

Hi! @embeddedmz

Im working with c++ code in Ubuntu and want to upload files/images to my FTP server. See attached images. How could I solve this? I have installed libcurl.

ftp terminal

Thanks in advance!

victoriastraberg avatar Apr 19 '23 09:04 victoriastraberg

Hello,

First of all, you must put your code inside a function (ex: int main() { // put code here }).

I ll try to give you an example before the end of the day that you can build on Ubuntu without CMake.

If you don't connect a secure FTP server (SFTP, FTPS/FTPES), you don't need to use the methode SetInsecure(true). Also, if the FTP server is not an active one (very rare), you must not set active to true.

Regards.

embeddedmz avatar Apr 19 '23 11:04 embeddedmz

Thank you very much!! I will put the code inside an upload() function which will have an input argument as a string. The input variable is a JPG image. @embeddedmz

victoriastraberg avatar Apr 19 '23 12:04 victoriastraberg

@victoriastraberg I tested this example with an FTP server hosted at 192.168.1.17:21 on my local network and a user account named "test" with a password "0123456789C++" :

#include "FTPClient.h"

#include <iostream>

using namespace embeddedmz;

int main()
{
     // CFTPClient is allocated on the main function's stack
     CFTPClient ftpClient([](const std::string& strLogMsg)
     { std::cout << strLogMsg << std::endl; });
     
     // Initialize a session
     ftpClient.InitSession("192.168.1.17", 21, "test", "0123456789C++");

     // Create dummy test file
     std::ofstream testFileStream("test_upload.txt");
     testFileStream << "This file is uploaded via FTPClient-C++ API.\n"
                       "If this file exists, that means that the test is passed.\n";
     testFileStream.close();

     // Upload "test_upload.txt" (relative path to the executable) to "/uploaded_file.txt" (distant file path on the FTP server)
     if (ftpClient.UploadFile("test_upload.txt", "uploaded_file.txt"))
     {
         std::cout << "OK.\n";
     }
     else
     {
         std::cout << "Error.\n";      
     }
     
     // Explicit session cleanup
     ftpClient.CleanupSession();
     
     // Remove dummy test file
     remove("test_upload.txt");
}

You can copy/paste that code in a main.cpp file that you can place in the same directory as the ftpclient-cpp/FTP/ and run this command in a terminal to compile the program : g++ -DLINUX main.cpp FTPClient.cpp CurlHandle.cpp -lcurl -o testUpload

Explanations : -DLINUX : you define a preprocessor macro 'LINUX' so you can enable the parts of the code that are intended for a Linux platform (it's like adding #define LINUX before #include "FTPClient.h"). -lcurl : You link the executable to libcurl shared object (library). -o testUpload : The generated program will be named testUpload I didn't add an argument to tell the compiler where the header files (.h) are (the argument is -I. the dot represents the current directory) since they are in the same directory as the source code cpp files.

To run the program : ./testUpload

embeddedmz avatar Apr 19 '23 20:04 embeddedmz

It works! Thank you! @embeddedmz

See attached image below. I get these warnings when I write -DLINUX and when I remove -DLINUX I get "could not find #include <direct.h>..." How come?

screenshot

victoriastraberg avatar Apr 24 '23 08:04 victoriastraberg

LINUX preprocessor macro must be defined because in the header file there's these preprocessor instructions

#ifndef LINUX                            // If LINUX macro is NOT defined (e.g. we are compiling on MS Visual Studio) include <direct.h>
#include <direct.h>                  // mkdir() function in defined in <direct.h> on Windows platform
#endif

<direct.h> is a header that exists only with Microsoft Visual Studio C/C++ API and contains mkdir() function used to create a directory. LINUX macro must be defined so that the C++ GNU compiler's preprocessor doesn't include it in the code that will be compiled.

You can ignore the warnings, they are related to obsolete elements in newer versions of libcurl. You can't see them if the LINUX macro processor is not defined because the compiler stops when it comes across the error related to <direct.h>.

embeddedmz avatar Apr 24 '23 09:04 embeddedmz

@embeddedmz Ok, thanks! :) Unfortunately I get every file stored in my local folder. How could I just upload the file without saving it locally?

victoriastraberg avatar Apr 26 '23 14:04 victoriastraberg

You can specify the absolute path to the file e.g. "/home/user/test_upload.txt". In the example above, I used a relative path but you can also use absolute paths.

Example : ftpClient.UploadFile("/home/user/test_upload.txt", "ftp_upload_dir/uploaded_file.txt")

On Windows : ftpClient.UploadFile("C:\\test_upload.txt", "ftp_upload_dir/uploaded_file.txt")

embeddedmz avatar Apr 26 '23 14:04 embeddedmz

@embeddedmz

Yes exactly. I already do like this - the problem is that the image still gets saved in the code folder. See here:

image1

victoriastraberg avatar Apr 26 '23 15:04 victoriastraberg

Can you show me the code using the upload() function ? (by the way, you don't need to use c_str() method when concatenating strings and when using UploadFile()).

I want to see how the image is stored in memory.

UploadFile has this "overloading" :

   bool UploadFile(std::istream &inputStream, const std::string &strRemoteFile, const bool &bCreateDir = false,
                   curl_off_t fileSize = -1) const;

Depending on the code that retrieves an image from the camera and keeps it somewhere in memory, I could help you write the code that uses this overloading. Something like this :

      unsigned char* mybuffer;
      size_t length;
      // allocate, fill, set length, as before

     std::string data(mybuffer, length);
     std::istringstream mb(data);

      // Upload stream
      ftpClient.UploadFile(mb, "image.jpg");

I can also add an overloading to the API having this signature if you want : bool CFTPClient::UploadFile(const unsigned char* dataPtr, const size_t dataLength, const std::string &strRemoteFile, const bool &bCreateDir)

embeddedmz avatar Apr 26 '23 15:04 embeddedmz