embeddedmz / ftpclient-cpp Goto Github PK
View Code? Open in Web Editor NEWC++ client for making FTP requests
License: MIT License
C++ client for making FTP requests
License: MIT License
Hi!
I want to upload an image from C++ project to a ftp server. I have created an upload function in c++ and I am working in Ubuntu Linux. The FtpClient.h file is located in my include folder, but I get "fatal error: direct.h: No such file or directory
23 | #include <direct.h> // mkdir".
See my code below. The param argument is a string path to the image. How should I work further?
Thanks in advance!
void upload(std::string& param)
{
void(const std::string&)
CFTPClient FTPClient([](const std::string& strLogMsg){ std::cout << strLogMsg << std::endl; });
FTPClient.InitSession("host", port, "user", "password");
FTPClient.SetActive(true);
FTPClient.UploadFile("C:/Desktop/upload.txt", "/ftp_folder/test_upload.txt");
FTPClient.CleanupSession();
}
Already done in https://github.com/embeddedmz/mailclient-cpp
Hi,
Maybe it is my system problem, but on ubuntu 16.04 with
libcurl4-gnutls-dev (7.47.0-1ubuntu2.19)
it fails to connect with FTPES type of server throwing an error:
"[FTPClient][Error] Unable to connect to remote folder / (Error = 1 | Unsupported protocol)."
But there is a fix for this, when connecting to FTPES server, you don't need to specify "ftpes://"
but just a regular "ftp://" instead.
change on line 206:
case FTP_PROTOCOL::FTPES: strURL = "ftp://" + strURL; //libcurl does not recognize 'ftpes' it should be just 'ftp'! break;
Hello,
are there any plans of implementing a parallelization with curl multi handles? I am especially interested in parallel upload (I have 6 directories with ~800 files each so doing it file-by-file takes a reaaaaaally long time).
I might even be interested to help implement that, however I don't have much experience with creating libraries, especially cross-platform...
Also, I think it would be nice if any action that failed (upload, download, etc) was automatically redone.
Add DEFINE_ENUM_FLAG_OPERATORS(SettingsFlag) if WINDOWS or _WINDOWS or _WIN32 is defined!
Hi,
Thanks for your work,
I have a problem when I try to upload a file to NAS server over FTP protocol with port 3090. This is the log file I get in debug mode
`[DEBUG] cURL debug log [0]: - Trying ServerAddress:3090...
[DEBUG] cURL debug log [1]: - 257 "/folderTest/aaa" - Directory successfully created
[DEBUG] cURL debug log [2]: - CWD aaa
[DEBUG] cURL debug log [1]: - 250 CWD command successful
[DEBUG] cURL debug log [2]: - EPRT |1|192.168.0.100|53839|
[DEBUG] cURL debug log [1]: - 500 Illegal EPRT command
[DEBUG] cURL debug log [0]: - disabling EPRT usage
[DEBUG] cURL debug log [0]: - Hostname 192.168.0.100 was found in DNS cache
[DEBUG] cURL debug log [2]: - PORT 192,168,0,100,199,61
[DEBUG] cURL debug log [1]: - 500 Illegal PORT command
[DEBUG] cURL debug log [0]: - Failed to do PORT
[DEBUG] cURL debug log [0]: - Remembering we are in dir "//folderTest//aaa//"
[DEBUG] cURL debug log [0]: - Uploaded unaligned file size (0 out of 4212503 bytes)`
Making a folder on the server is ok but uploading file is a failure. It looks like port 3090 was denied on the server.
But when I try to use the command "curl -p --insecure "ftp://file_remote" --user "user:password" -T "file_local", it's ok.
Any solution was appreciated!
I'm using curl version 7.68.0
Thanks so much,
Hi, I would like to use this library for a project where I need to send "APPEND" commands to a remote file, does this library allows this operation?
libcurl global initialization is currently handled in the constructor with a static mutex and a counter of CFTPClient objects :
s_mtxCurlSession.lock();
if (s_iCurlSession++ == 0)
{
curl_global_init(CURL_GLOBAL_ALL);
}
s_mtxCurlSession.unlock();
ditto for the global cleanup in destructor :
s_mtxCurlSession.lock();
if (--s_iCurlSession <= 0)
{
curl_global_cleanup();
}
s_mtxCurlSession.unlock();
If in your application, there's only ftpclient-cpp using libcurl, there's no issues.
However, if you use it with another 3rd party library (e.g. httpclient-cpp) that initializes curl in a thread different from any other thread where CFTPClient objects live, there will be undefined behavior (crashs, bugs, dragons, clowns etc...). As stated here : https://curl.haxx.se/libcurl/c/curl_global_init.html curl_global_init isn't thread safe.
I think it's better to remove this stupid "hack" and explicitly call curl_global_init(CURL_GLOBAL_ALL); at the beginning of your program and call curl_global_cleanup(); at the end of it. Adding a static method is a good way to achieve that.
hi, embeddedmz!
thank for share the great proj, i want to know which curl version is to used, i test the newest curl version 8.4.0, but the DownloadWildcard failed and some compile warning. and I use the lib on ubuntu 20.04 in virtual machine, the memory usage will increasing to 30%(memory leak?), i don't known how to do? Have you encountered similar problems?but the same code on windows, every thing is ok. expect your reply.
ftpclient-cpp/FTP/FTPClient.cpp
Line 185 in cb78fb5
this line changes ftp://127.0.0.1/
to ftp:////127.0.0.1////
shouldn't be?
ReplaceString(strURL, "//", "/");
for (int i = 0;i < 10000; i++)
{
CFTPClient::FileInfo ResFileInfo = { 0, 0.0 };
bool bOkInfo = FTPClient.Info("/a.txt", ResFileInfo);
}
when i = 47
logger say
[FTPClient][Error] Unable to get file /a.txt's info (Error = 23 | Failed writing received data to disk/application).
so i modify CFTPClient::Info add 3 line and i seem work ok;
Hi @ksv87
The pipeline always fails for MSVC https://github.com/embeddedmz/ftpclient-cpp/actions/runs/2429647821
Apparently, it's because the VS C++ compiler "cl" is missing (by the way, it's github that manages the pipeline ?)
Is it better to remove MSVC from the pipeline file ?
Thanks.
Hi, I interested to use this build on my project, but I have problems to connect using sftp to my server.
I tried:
FTPClient.InitSession("xxx.xx.xx.xx:xx, 22, "username", "password");
But on console I have an error 1 indicating protocol not supported.
It works good using FTP protocol, but you know it's not recommend to use.
Please help,
Thanks
When my ftp server uses port 2121.
my code:
CFTPClient FTPClient([](const std::string& strLogMsg){ std::cout << strLogMsg << std::endl; }); FTPClient.InitSession(ftpserver.com,2121,user,password); FTPClient.UploadFile(src_file, dst_file); FTPClient.CleanupSession();
i will get "(Error = 7 | Couldn't connect to server)."
it looks like ftp url Missing port information
If I use DownloadWildcard() together with a ProgressCallback, the given progress is always just showing the progress of the currently downloaded file and not of the overall progress. So if there are several files matched by the wildcard, there is no way of telling the overall progress.
Sorry to bug you again, but i'm no expert in c++ templates, and can't wrap my head around
how to pass a class member method to:
ftp->SetProgressFnCallback(this, &Class::method);
it gives:
no known conversion for argument 2 from ‘int (MainWindow::)(void, double, double, double, double)’ to ‘const ProgressFnCallback& {aka const std::function<int(void*, double, double, double, double)>&}’
@embeddedmz This is nice ftpclient and I think it would be nice to add it as reciepe to conan repo Conan.
What do you think?
FTPClient.InitSession("ftp://172.21.32.99", 21, "admin", "admin");
FTPClient.UploadFile("1.txt", "2.txt");
When I run the program, Error message: [FTPClient][Error] Unable to upload file 1.txt (Error = 3 | URL using bad/illegal format or missing URL).
I find something wrong in function ParseURL:
strURL is "ftp://172.21.32.99/2.txt", after executing the next statement:
ReplaceString(strURL, "/", "//");
strURL turn into "ftp:////172.21.32.99//2.txt", it's bad format
hi i have a advice
if the file name have [#] it dot not work
and i found CTFPClient::ParseURL do not process [#]
When I launch unit tests many times, sometimes some unit tests fail with a time out error (curl error code 28).
Even if I don't define a timeout, there's still timeout errors.
When an operation fails, I recommend coding a retry mechanism (with a while loop and a maximum number of retries) in your applications.
libcurl已经nmake后编译出了libcurl_a.lib,并且在Qt里做了配置
`QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
win32 {
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
INCLUDEPATH += "D:\curl-8.0.1\builds\libcurl-vc15-x86-release-static-ipv6-sspi-schannel\include"
QMAKE_CXXFLAGS += /utf-8
LIBS += -L"D:\curl-8.0.1\builds\libcurl-vc15-x86-release-static-ipv6-sspi-schannel\lib" \
-llibcurl_a
} else {
}`
依然提示:
D:\test\curlTest\FTPClient.cpp:631: error: C3861: “Utf8ToUtf16”: 找不到标识符
请问这是为何?
You can add on top of FTPClient.h, right after FTPCLIENT_VERSION define:
#ifdef QT_CORE_LIB #include <QtGlobal> #ifdef Q_OS_LINUX #define LINUX #endif #ifdef Q_OS_WINDOWS #define WINDOWS #endif #endif
Under Windows, where file names are not coded in UTF-8 but in UTF-16 and code pages (a mess !), the name of the files downloaded with DownloadWildcard (and maybe other methods) and having special characters (e.g. french accents or using not latin characters e.g. arabic or chinese) will not be written correctly.
I have no idea how to fix this now.
std::string folder = "pictures";
std::string filelist;
ftp.List(folder, filelist);
if i call the List interface like this, i can't get expected results, the auctual results filelist is one level above the directory. then i fix the folder suffix with /, the results is my expected!
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.
Thanks in advance!
compile with visual studio 2019, errors are "cannot identify Utf8ToUtf16"
In DownloadWildcard method must exclude “.” And “..” Dir values because happen a infinite loop on “.” value calling itself recursively.
Hi,
Thank you and contributors for their efforts! Much appreciated.
This is actually a request for guidance rather than an issue. Let me know if I should move it somewhere else. StackOverflow maybe?
I can build this project on Windows 10 using a slightly modified version of your instructions. Basically I added a vcpkg.json file with the dependencies and then called cmake e.g. [path to cmake] -B build -S . -DCMAKE_TOOLCHAIN_FILE=[path to vcpkg cmake file]
This works.
My understanding is that this project is meant to be statically built into another project with a main function (correct me if I am wrong).
So I created a project and added this project as a sub-directory to it. Basically a more complicated set up of this official CMake tutorial
My project directory looks like this:
[project folder]/ftp_automation_cpp/ftpclient-cpp/
[project folder]/ftp_automation_cpp/CMakeLists.txt
[project folder]/ftp_automation_cpp/ftp_automation.cpp
[project folder]/ftp_automation_cpp/vcpkg.json
vckpg.json
{
"dependencies": [
{
"name" : "curl",
"features" : [ "openssl", "ssh" ]
},
"gtest"
]
}
ftp_automation.cpp
#include <iostream>
#include <string>
#include "FTPClient.h"
int main(int argc, char* argv[])
{
std::cout << "Hello, world!"
<< std::endl;
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.27)
project(FTP_Automation VERSION 0.1)
add_executable(ftp_automation ftp_automation.cpp)
add_subdirectory(ftpclient-cpp)
target_include_directories(ftp_automation PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/ftpclient-cpp"
)
add_library(FTPClient STATIC)
target_sources(FTPClient PUBLIC "${PROJECT_SOURCE_DIR}/ftpclient-cpp/FTP/FTPClient.cpp")
target_sources(FTPClient PUBLIC "${PROJECT_SOURCE_DIR}/ftpclient-cpp/FTP/CurlHandle.cpp")
target_link_libraries(ftp_automation PUBLIC FTPClient)
This builds and generates the .sln file but on opening it VS 2022 says there is already a ftpclient-cpp project and the cpp files are duplicated in my project.
I built libcurl 8.8.0, connected it to your library, and successfully built ftpclient.lib, now I created a project for testing, connected the library, but when I run it I get the following errors:
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_slist_append.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_slist_free_all.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_strerror.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_init.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_setopt.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_perform.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_cleanup.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_getinfo.
1>ftpclient.lib(FTPClient.obj) : error LNK2001: unresolved external symbol __imp__curl_easy_reset.
1>ftpclient.lib(CurlHandle.obj) : error LNK2001: unresolved external symbol __imp__curl_global_init.
1>ftpclient.lib(CurlHandle.obj) : error LNK2001: unresolved external symbol __imp__curl_global_cleanup.
1>C:\Users\FireRun\Desktop\ftp\ftp\Release\ftp.exe : fatal error LNK1120: unresolved external elements: 11
For testing I used minimal code:
#include <iostream>
#include "FTP/FTPClient.h"
#pragma comment(lib, "ftpclient.lib")
int main()
{
embeddedmz::CFTPClient FTPClient([](const std::string& strLogMsg) { std::cout << strLogMsg << std::endl; });
std::cout << "Hello World!\n";
}
The CFTPClient
missing ability to upload data stored in memory. My proposal is the following: extend the CFTPClient
with public methods:
bool UploadFile(read_callback_t read_callback, void* userData, const std::string &strRemoteFile, const bool &bCreateDir = false) const;
bool UploadFile(std::istream &isData, const std::string &strRemoteFile, const bool &bCreateDir = false) const;
First one correspond to CURLOPT_READFUNCTION
and second one is useful wrapper for std::istream
. Implementation of
bool UploadFile(const std::string &strLocalFile, const std::string &strRemoteFile, const bool &bCreateDir = false) const;
could be updated therefore to open strLocalFile
with std::ifstream
and call overload 2).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.