Added CMakeLists.txt to File-Downloader

This commit is contained in:
2026-04-07 10:40:19 +02:00
commit 2c1fbaf4c6
10 changed files with 399 additions and 0 deletions

7
CMakeLists.txt Normal file
View File

@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.16)
add_library(FileDownloader SHARED downloader.cpp console.cpp)
target_include_directories(FileDownloader
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 ezBinary
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

23
Makefile Normal file
View File

@@ -0,0 +1,23 @@
# Makefile for FileDownloader project
# Works on macOS & linux
CC = g++
FLAGS = -Wall -std=c++11
LIBS = -lcurl
all: FileDownloader
FileDownloader: main.o downloader.o console.o
$(CC) $(FLAGS) $^ -o $@ $(LIBS)
main.o: main.cpp
$(CC) $(FLAGS) -c $<
downloader.o: downloader.cpp
$(CC) $(FLAGS) -c $<
console.o: console.cpp
$(CC) $(FLAGS) -c $<
clean:
rm -f *.o FileDownloader

79
README.md Normal file
View File

@@ -0,0 +1,79 @@
# File Downloader
A simple File Downloader using C++ and libcURL.
## Table of Contents
- [Introduction](#introduction)
- [Features](#features)
- [Compilation](#compilation)
- [Contributions](#contributions)
- [License](#license)
- [Feedback](#feedback)
## Introduction
The File Downloader is a C++ project developed using the libcURL library. It facilitates downloading files from provided URLs using the cURL library and provides real-time download progress information, including download speed, percentage completion, and total download size.
<img width="1061" alt="screenshot_filedownloader" src="https://github.com/ezBinary/File-Downloader/assets/164413461/3a934709-5c81-4125-ba4a-a9a2396e7f6c">
## Features
- Downloads files from provided URLs using cURL.
- Displays real-time download progress, including percentage completion and download speed.
- Provides a simple and easy to use command line interface for downloading files.
## How to Use
1. **Input URL**: Provide the download link of the file you want to download.
2. **Start Download**: Press enter to initiate the download process.
3. **Monitor Progress**: Monitor the download progress, including the percentage completed and the download speed.
4. **Completion**: Once the download is complete, the file will be available for use.
## Why File Downloader?
File Downloader was developed as a training project to learn more about the capabilities of the cURL and enhance understanding of network programming in C++. It aims to provide a practical example for those interested in integrating file downloading functionality into their projects.
## Compilation
To use File Downloader, simply clone the repository and compile the source code using your preferred C++ compiler. Ensure that you have the libcURL library installed on your system.
### Compiling with Different Compilers
File Downloader can be compiled using various compilers on different platforms. Below are instructions for compiling the project with commonly used compilers:
#### 1. g++
```bash
g++ main.cpp downloader.cpp console.cpp -o FileDownloader -lcurl
```
#### 2. clang++
```bash
clang++ main.cpp downloader.cpp console.cpp -o FileDownloader -lcurl
```
#### 3. Microsoft Visual C++ (MSVC)
```bash
cl /EHsc main.cpp downloader.cpp console.cpp /link /out:FileDownloader.exe
```
### Platform Compatibility
This project's Makefile is designed to work seamlessly on both macOS and Linux systems. Below are instructions on how to use it :
To compile the project on macOS and Linux systems, simply navigate to the project directory in the terminal and run the `make` command. This will compile the source files and generate the executable `FileDownloader`.
---
Feel free to let me know if you need any further modifications!
## Contributions
Contributions to File Downloader are welcome! Feel free to fork the repository, make improvements, and submit pull requests.
## License
This project is licensed under the [MIT License](LICENSE). Feel free to use and modify it according to your needs.
## Disclaimer
File Downloader is provided as-is, without any warranties or guarantees. I am not liable for any damages or issues arising from the use of this software.
## Feedback
If you have any feedback, suggestions, or issues, please feel free to [open an issue](https://github.com/ezBinary/File-Downloader/issues) or [contact me](mailto:ez.like.binary@proton.me). I appreciate your input!
Enjoy using File Downloader for your file downloading needs!

8
common.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <iostream>
#include <string>
#include <curl/curl.h>
#include <chrono>
#include <thread>
#include <iomanip>

54
console.cpp Normal file
View File

@@ -0,0 +1,54 @@
#include "console.h"
#include <string>
#include <regex>
// Check the validate URL format
bool isValidURL(const std::string& url)
{
// Regular expression to validate URL format
std::regex urlRegex("(https?|ftp)://[^\\s/$.?#].[^\\s]*");
return std::regex_match(url, urlRegex);
}
// Get a valid URL from the user
std::string console::getValidURL() {
std::string url;
while (true)
{
std::cout << "Enter the URL or 'q' to quit: ";
std::getline(std::cin, url);
if (url == "q" || url == "Q") {
std::cout << "Input cancelled." << std::endl;
exit(0);
}
if (isValidURL(url)) {
return url;
}
std::cout << "Invalid URL format. Please enter a valid URL or 'q' to cancel." << std::endl;
}
}
// Print Stylish Progress Bar
void console::drawStylishProgressBar(double progress, int width) {
int completedBlocks = static_cast<int>(progress * width);
int remainingBlocks = width - completedBlocks;
int i;
// Clear previous output
std::cout << "\r" << std::flush;
// Print new progress bar
std::cout << "[";
for (i = 0; i < completedBlocks; ++i) {
std::cout << "\u2588"; // Full block Unicode character
}
for (i = 0; i < remainingBlocks; ++i) {
std::cout << "\u2591"; // Light shade Unicode character
}
std::cout << "] " << std::fixed << std::setprecision(0) << (progress * 100) << "%" << std::flush;
}

10
console.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "common.h"
bool isValidURL(const std::string& url) ;
namespace console
{
std::string getValidURL();
void drawStylishProgressBar(double progress, int width);
}

149
downloader.cpp Normal file
View File

@@ -0,0 +1,149 @@
#include "downloader.h"
// Convert bytes to human readable format
std::string formatBytes(curl_off_t bytes)
{
static const char *suffixes[] = {"B", "KB", "MB", "GB", "TB"};
int suffixIndex = 0;
double adjustedBytes = static_cast<double>(bytes);
while (adjustedBytes >= 1024 && suffixIndex < sizeof(suffixes) / sizeof(suffixes[0]) ) {
adjustedBytes /= 1024.0;
suffixIndex++;
}
return std::to_string(adjustedBytes) + " " + suffixes[suffixIndex];
}
// Progress callback function
int FileDownloader::progressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
std::string SpeedStr;
DownloadProgress *progress = static_cast<DownloadProgress*>(clientp);
double percent;
double speed;
// Update progress data
progress->bytesDownloaded = dlnow;
progress->totalSize = dltotal;
// Calculate download completion percentage
percent = (dltotal > 0) ? (dlnow * 100.0 / dltotal) : 0.0;
// Calculate download speed
auto elapsedTime = std::chrono::steady_clock::now() - progress->startTime;
speed = progress->bytesDownloaded / (std::chrono::duration_cast<std::chrono::milliseconds>(elapsedTime).count() / 1000.0); // bytes per second
// Clear previous progress bar
std::cout << "\r";
// Display progress bar
console::drawStylishProgressBar(percent / 100.0,50);
// Display download size information
std::cout << " (" << formatBytes(progress->bytesDownloaded) << " of " << formatBytes(progress->totalSize) << ")";
// Display download speed
SpeedStr = " | Speed: " + formatBytes(speed) + "/s ";
std::cout << SpeedStr.c_str();
std::cout.flush(); // Ensure immediate output
return 0;
}
bool FileDownloader::Downloader()
{
CURL *curl = curl_easy_init();
DownloadProgress progress;
CURLcode res;
FILE *file;
if (!curl) {
std::cerr << "Error initializing curl." << std::endl;
return false;
}
// Set the URL
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// Set progress callback function
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); // Enable progress data
// Open file hanndle for writing
file = fopen(filename.c_str(), "wb");
if (!file) {
std::cerr << "Error opening file for writing" << std::endl;
curl_easy_cleanup(curl);
return false;
}
// Set file as the target for the download
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
// Record start time
progress.startTime = std::chrono::steady_clock::now();
// Perform the request
res = curl_easy_perform(curl);
// Check for errors
if (res != CURLE_OK)
{
std::cerr << "\ncurl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
return false;
} else
{
std::cout << "\nDownload completed successfully!" << std::endl;
}
return true;
}
FileDownloader::FileDownloader(const std::string& i_url) : url(i_url), curl(nullptr), file(nullptr)
{
// Initialize libcurl
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
{
std::cerr << "Error initializing libcurl." << std::endl;
}
std::size_t found = url.find_last_of("/");
if (found != std::string::npos)
{
filename = url.substr(found + 1);
}
else
{
// invalid URL without filename
std::cerr << "Error: Invalid URL format." << std::endl;
}
}
FileDownloader::~FileDownloader()
{
// close curl handle
curl_easy_cleanup(curl);
// close file handle
fclose(file);
// If the download process was unsuccessful, simply delete the corrupted downloaded file.
if(!check)
{
std::remove(filename.c_str());
}
// close global init
curl_global_cleanup();
}
void FileDownloader::download()
{
check = FileDownloader::Downloader();
}

35
downloader.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include "console.h"
class FileDownloader {
private:
// Struct to encapsulate download progress data
struct DownloadProgress {
curl_off_t bytesDownloaded;
curl_off_t totalSize;
std::chrono::steady_clock::time_point startTime;
DownloadProgress() : bytesDownloaded(0), totalSize(0), startTime(std::chrono::steady_clock::now()) {}
};
std::string url;
std::string filename;
CURL* curl;
FILE* file;
bool check;
bool Downloader();
static int progressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
public:
FileDownloader(const std::string& xurl);
~FileDownloader();
void download();
};

13
main.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "downloader.h"
int main()
{
// Get a valid URL from the user
std::string i_url = console::getValidURL();
// Download
FileDownloader fdl(i_url.c_str());
fdl.download();
return 0;
}