How to assign File path to variable in c++ - c++

I have a program which calculates md5 hash.
I can enter the text and it will generate the md5 code.
I want to get files from computer, for example text file and generate md5 for that. The problem is that i don't know how to get the file location and assign it to variable so i can put that variable in md5 generator function.
cout << "md5 of 'grape': " << md5("example") << endl;
as you can see in the above code i enter the md5 function argument which is "example" string, so i want something like this
string foo = "C:\\Users\\User\\Downloads\\1.txt";
cout << "md5 of 'grape': " << md5(foo) << endl;
so this will calculate md5 for "C:\Users\User\Downloads\1.txt" string, but i want to calculate the 1.txt file's md5.

One way to do it is by reading the whole file into a string and passing it to md5 function like this (I assume you are using zedwood's md5):
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "md5.h"
int main()
{
MD5 md5;
std::ifstream ifs("C:\\Users\\User\\Downloads\\1.txt", std::ios::binary);
if (ifs)
{
std::ostringstream oss;
oss << ifs.rdbuf();
std::string s(oss.str());
md5.update(s.data(), s.size());
md5.finalize();
std::cout << md5.hexdigest() << std::endl;
}
return 0;
}
This should work with non-text files too.

Related

C++ Error in creating the file (name based on other file name)

I have a problem with creating a file, whose name is a little bit modified from some other file's name.
But if the new name is not based on another name - the program works - but I need to use that first method.
I used backslash (\b) to remove ".srt" from the original file name to modify the copy - in this program, I cannot modify path_file_1 and path_file_2, so I cannot just miss the extension and add it later when I finished preparing the copy.
Here's the code:
#include <iostream>
#include <fstream>
int main()
{
std::cout << "Starrting!" << std::endl;
std::string path_file_1 = "Sub-File1.srt";
std::string path_file_2 = "Sub-File2.srt";
std::string path_file_new = path_file_1 + "\b\b\b\b-corr.srt";
//std::string path_file_new = "Sub-File1-corr.srt";
//this works!
std::cout << path_file_1 << std::endl;
std::cout << path_file_new << std::endl;
//Creating a new file
std::fstream file;
file.open(path_file_new, std::ios::out | std::ios::binary);
if (!file)
{
std::cout << "Error in creating file!!!";
return 0;
}
std::cout << "File created successfully." << std::endl;
file.close();
}
Here's the output:
Starrting!
Sub-File1.srt
Sub-File1-corr.srt
Error in creating file!!!
Adding \b\b\b\b to your string adds 4 backspace characters. It does not remove 4 chars from the string.
This would work:
std::string path_file_new = path_file_1.substr(0, path_file_1.size()-4) + "-corr.srt";
As others have stated, you can't use backslash characters to remove characters, you would need to use string::substr() instead in this particular situation.
If you are using C++17 or later, you can use the <filesystem> library to manipulate file paths more easily, eg:
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
std::cout << "Starrting!" << std::endl;
fs::path path_file_1 = "Sub-File1.srt";
fs::path path_file_new = path_file_1.stem(); // removes the extension...
path_file_new += "-corr.srt";
std::cout << path_file_1 << std::endl;
std::cout << path_file_new << std::endl;
//Creating a new file
std::ofstream file(path_file_new, std::ios::binary);
if (!file.is_open())
{
std::cout << "Error in creating file!!!";
return 0;
}
std::cout << "File created successfully." << std::endl;
file.close();
}
Online Demo
Using backspaces for this won't cut it, unfortunately. Displaying the filename is misleading because they will have the desired effect on the display, but the filename itself will not be correct because it will contain actual backslash characters.
Instead, you want what Ted says in his answer - make a shortened version of the original string and add the desired suffix.

How to read and output how many Bytes a folder has in it using C++ 17 filesystem on windows

I have a C++ program that takes a directory, like "D:\P4Test", and attempts to tell me how many bytes are in each subfolder and file within that directory. The code I currently have looks like this:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdint>
#include <sstream>
#include <filesystem>
using namespace std;
namespace fs = std::filesystem;
using namespace std::filesystem;
int main()
{
string path = "D:\\P4Test";
for (const auto& entry : directory_iterator(path)) {
cout << entry.path() << std::endl;
uintmax_t fsize = file_size(entry.path());
cout << " ||| " << fsize << endl;
}
}
Yes, it has a lot of unnecessary includes and such, but that's for future things.
When I run this code, I don't get what I want. Here's a picture of what's in that directory, and the output.
As you can see, the output looks good, but it does not give me the bytes for what's in the folders called "Two" & "Three".
Both folders have a text file in them that's 5 bytes, but they report back 0.
Can anyone help me figure out why, and show me how to make the folders show their bytes, or direct me to where I can figure this out?
It looks like you are trying to do a recursive file size check, but you do not actually recurse into the directories. 1 way to do this is to stasrt with a function gets all of the file sizes:
void folder_size(std::filesystem::path path) {
for (const auto& entry : directory_iterator(path)) {
cout << entry.path() << std::endl;
uintmax_t fsize = file_size(entry.path());
cout << " ||| " << fsize << endl;
}
}
Now we simply a special case to deal with if the file type is a directory, we can do this with std::filesystem::directory_entry::is_directory:
if (entry.is_directory()) {
// Handle the directory
}
So how do we handle the directory, well we have a function that we made that takes a directory path and goes through it. Lets call that:
if (std::filesystem::is_directory(entry.path())) {
folder_size(entry.path())
}
Putting it all together:
void folder_size(std::filesystem::path path) {
for (const auto& entry : directory_iterator(path)) {
cout << entry.path() << std::endl;
uintmax_t fsize = file_size(entry.path());
cout << " ||| " << fsize << endl;
if (std::filesystem::is_directory(entry.path())) {
folder_size(entry.path())
}
}
}
NOTE: All of the above is example code. No compilation check has been conducted.

How do I read words from a file, assign them to an array and analyze its content?

I (a student whose professor encourages online research to complete projects) have an assignment where I have to analyze the contents of a file (frequency of certain words, total word cout, largest and smallest word) and I'm getting stuck on even opening the file so the program can get words out. I've tried to just count the words that it reads and i get nothing. As I understand it, the program should be opening the selected .txt file, going through its contents word by word and outputing it right now.
Here's code:
#include <iostream>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>
string selected[100];
//open selected file.
ifstream file;
file.open(story.c_str());
string line;
if (!file.good())
{
cout << "Problem with file!" << endl;
return 1;
}
while (!file.eof())
{
getline(file, line);
if (line.empty())
continue;
istringstream iss(line);
for (string word; iss >> word;)
cout << word << endl;
```
Because of the simplicity of the attached code, I will not give detailed explanations here. With the usage of std::algorithm every task can be performed in a one-liner.
We will read the complete source file into one std::string. Then, we define a std::vector and fill it with all words. The words are defined by an ultra simple regex.
The frequency is counted with a standard approach using std::map.
#include <fstream>
#include <string>
#include <iterator>
#include <vector>
#include <regex>
#include <iostream>
#include <algorithm>
#include <map>
// A word is something consiting of 1 or more letters
std::regex patternForWord{R"((\w+))"};
int main() {
// Open file and check, if it could be opened
if (std::ifstream sampleFile{ "r:\\sample.txt" }; sampleFile) {
// Read the complete File into a std::string
std::string wholeFile(std::istreambuf_iterator<char>(sampleFile), {});
// Put all words from the whole file into a vector
std::vector<std::string> words(std::sregex_token_iterator(wholeFile.begin(), wholeFile.end(), patternForWord, 1), {});
// Get the longest and shortest word
const auto [min, max] = std::minmax_element(words.begin(), words.end(),
[](const std::string & s1, const std::string & s2) { return s1.size() < s2.size(); });
// Count the frequency of words
std::map<std::string, size_t> wordFrequency{};
for (const std::string& word : words) wordFrequency[word]++;
// Show the result to the user
std::cout << "\nNumber of words: " << words.size()
<< "\nLongest word: " << *max << " (" << max->size() << ")"
<< "\nShortest word: " << *min << " (" << min->size() << ")"
<< "\nWord frequencies:\n";
for (const auto& [word, count] : wordFrequency) std::cout << word << " --> " << count << "\n";
}
else {
std::cerr << "*** Error: Problem with input file\n\n";
}
return 0;
}

Writing to a .PGM file using C++

For some reason, I can't write anything to a .PGM file. The following code compiles without errors but nothing is written to the .PGM file it creates. I'm fairly new to C++ and pretty unfamiliar with working with strings in this syntax.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <sstream>
int main(){
// Initialize variables.
const int ncols = 30;
const int nrows = 20;
const int maxval = 255;
std::string filename;
// Prompt user for filename.
std::cout << "What would you like to name the file of the PGM image? Please include .PGM at the end of your name." << std::endl;
// Uses getline() function to retrieve input from user into a string.
std::getline(std::cin, filename);
// Creates output stream object to use with managing the file.
std::ofstream fileOut(filename.c_str(),std::ios_base::out
|std::ios_base::binary
|std::ios_base::trunc
);
fileOut.open(filename.c_str());
fileOut << "P2" << " " << ncols << " " << nrows << " " << maxval << "\n";
fileOut.close();
}
I know there is another SO question similar to this one, but I used that answer to get here. I can't even get it to write the header part and that's not even the point of the assignment. Can anyone help?

compressed length of a string by boost::iostreams

I have a string (of some fixed length), which I need to compress and then compare the compressed lengths (as a proxy for redundancy in the data or as a rough approximation to the Kolmogorov complexity). Currently, I am using boost::iostreams for compression, which seems working well. However, I don't know how to obtain the size of the compressed data. Can someone help, please?
The code snippet is
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/filesystem.hpp>
#include <string>
#include <sstream>
namespace io = boost::iostreams;
int main() {
std::string memblock;
std::cout << "Input the string to be compressed:";
std::cin >> memblock;
std::cout << memblock << std::endl;
io::filtering_ostream out;
out.push(io::gzip_compressor());
out.push(io::file_descriptor_sink("test.gz"));
out.write (memblock.c_str(), memblock.size());
std::cout << out.size() << std::endl;
return 0;
}
You can try adding boost::iostreams::counter to you chain between the compressor and sink and then calling it's characters() member to get number of bytes that went through it.
This works for me:
#include <boost/iostreams/filter/counter.hpp>
...
io::filtering_ostream out;
out.push(io::counter());
out.push(io::gzip_compressor());
out.push(io::counter());
out.push(io::file_descriptor_sink("test.gz"));
out.write (memblock.c_str(), memblock.size());
io::close(out); // Needed for flushing the data from compressor
std::cout << "Wrote " << out.component<io::counter>(0)->characters() << " bytes to compressor, "
<< "got " << out.component<io::counter>(2)->characters() << " bytes out of it." << std::endl;
I figured out yet another (and slightly slicker) way to achieve the compressed length of a string. I thought sharing it here, but basically it is simply passing the uncompressed string to a filtered buffer and copying the output back to a string:
template<typename T>
inline std::string compressIt(std::vector<T> s){
std::stringstream uncompressed, compressed;
for (typename std::vector<T>::iterator it = s.begin();
it != s.end(); it++)
uncompressed << *it;
io::filtering_streambuf<io::input> o;
o.push(io::gzip_compressor());
o.push(uncompressed);
io::copy(o, compressed);
return compressed.str();
}
Later one can easily get the size of the compressed string as
compressIt(uncompressedString).size()
I feel it is better for it does not required me to create an output file as previously.
cheers,
Nikhil
one other way would be
stream<array_source> input_stream(input_data,input_data_ize);
stream<array_sink> compressed_stream(compressed_data,alloc_compressed_size);
filtering_istreambuf out;
out.push(gzip_compressor());
out.push(input_stream);
int compressed_size = copy(out,compressed_stream);
cout << "size of compressed_stream" << compressed_size << endl;