I have googled this, but I am still confused about how to use it. I am making a file manager, and I want to be able t o copy and paste a file into a new directory. I know to copy I need to use file.copy(), but I am not sure how to implement it into my code.
I would like to do this using fstream.
If you are using the Win32 API then consider looking into the functions CopyFile or CopyFileEx.
You can use the first in a way similar to the following:
CopyFile( szFilePath.c_str(), szCopyPath.c_str(), FALSE );
This will copy the file found at the contents of szFilePath to the contents of szCopyPath, and will return FALSE if the copy was unsuccessful. To find out more about why the function failed you can use the GetLastError() function and then look up the error codes in the Microsoft Documentation.
void copyFile(const std::string &from, const std::string &to)
{
std::ifstream is(from, ios::in | ios::binary);
std::ofstream os(to, ios::out | ios::binary);
std::copy(std::istream_iterator(is), std::istream_iterator(),
std::ostream_iterator(os));
}
Here is my implementation to copy a file, you should take a look at boost filesystem since that library will be part of the standard c++ library.
#include <fstream>
#include <memory>
//C++98 implementation, this function returns true if the copy was successful, false otherwise.
bool copy_file(const char* From, const char* To, std::size_t MaxBufferSize = 1048576)
{
std::ifstream is(From, std::ios_base::binary);
std::ofstream os(To, std::ios_base::binary);
std::pair<char*,std::ptrdiff_t> buffer;
buffer = std::get_temporary_buffer<char>(MaxBufferSize);
//Note that exception() == 0 in both file streams,
//so you will not have a memory leak in case of fail.
while(is.good() and os)
{
is.read(buffer.first, buffer.second);
os.write(buffer.first, is.gcount());
}
std::return_temporary_buffer(buffer.first);
if(os.fail()) return false;
if(is.eof()) return true;
return false;
}
#include <iostream>
int main()
{
bool CopyResult = copy_file("test.in","test.out");
std::boolalpha(std::cout);
std::cout << "Could it copy the file? " << CopyResult << '\n';
}
The answer of Nisarg looks nice, but that solution is slow.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363851(v=vs.85).aspx
I don't know what you mean by copy and paste a file; that makes no sense. You can copy a file to another location and I assume that's what you are asking about.
In native C++, you can use:
The CopyFile function : http://msdn.microsoft.com/en-us/library/windows/desktop/aa363851%28v=vs.85%29.aspx
CopyFileEx function for more advanced options like progress notifications. http://msdn.microsoft.com/en-us/library/windows/desktop/aa363852%28v=vs.85%29.aspx
Using C makes C++ projects more portable. Here my sample code is a reference for you.
int file_copy(char* fn_dst, char* fn_src) {
FILE* pf = NULL;
char* buf = NULL;
int len = 0;
//get length of file src
pf = fopen(fn_src, "r");
if (pf == NULL) {
printf("[%s]Failed to fopen:%s\n", __func__, fn_src);
return -1;
}
fseek(pf, 0, SEEK_END);
len = ftell(pf);
fclose(pf);
//allocate buf
buf = (char*)malloc(len);
if (buf == NULL) {
printf("[%s]Failed to malloc\n", __func__);
return -1;
}
memset(buf, 0, len);
//read from file src
pf = fopen(fn_src, "rb");
if (pf == NULL) {
printf("[%s]Failed to fopen:%s\n", __func__, fn_src);
return -1;
}
fread(buf, 1, len, pf);
fclose(pf);
//write into file dst
pf = fopen(fn_dst, "wb+");
if (pf == NULL) {
printf("[%s]Failed to fopen:%s\n", __func__, fn_dst);
return -1;
}
fwrite(buf, 1, len, pf);
fclose(pf);
if (buf)
free(buf);
return 0;
}
System::IO::File::Copy("Old Path", "New Path");
Related
When trying to unzip an image file using libzip, I have run across the issue where in the image data, I hit a null byte and libzip zip_fread sees this as EOF and stops reading the file, resulting in a corrupted image. What is the best way to get handle the null byte when reading an image and extract the full image?
To clarify, text only files extract perfectly fine.
Below is the code used:
int FileHandler::ExtractFiles(std::string& path, std::string& file, bool is_test)
{
int err = 0;
std::string fullPath = path + "\\" + file;
zip* za = zip_open(fullPath.c_str(), 0, &err);
struct zip_stat st;
zip_stat_init(&st);
int number_of_entries = zip_get_num_entries(za, NULL);
for (zip_uint64_t i = 0; i < number_of_entries; ++i)
{
const char* name = zip_get_name(za, i, NULL);
std::string s_name = name;
size_t pos;
std::string backsl = "\\";
while ((pos = s_name.find(47)) != std::string::npos)
{
s_name.replace(pos, 1, backsl);
}
std::string fullFilePath = path + "\\" + s_name;
if(!is_test)
printf("Extracting: %s...\n", s_name.c_str());
std::string fullDir;
size_t found;
found = fullFilePath.find_last_of("\\");
if (found != std::string::npos)
{
fullDir = fullFilePath.substr(0, found);
}
struct zip_stat ist;
zip_stat_init(&ist);
zip_stat(za, name, 0, &ist);
char* contents = new char[ist.size];
zip_file* f = zip_fopen(za, name, 0);
// zip_fread to contents buffer
zip_fread(f, contents, ist.size);
if (CreateDirectory(fullDir.c_str(), NULL) || ERROR_ALREADY_EXISTS == GetLastError())
{
// writing buffer to file
if (!std::ofstream(fullFilePath).write(contents, ist.size))
{
return EXIT_FAILURE;
}
}
zip_fclose(f);
}
zip_close(za);
return EXIT_SUCCESS;
}
gerum was able to point me in the right direction. For anyone that is wondering or has the same issue, I had to open the ofstream in binary mode and that resolved the issue.
Original code:
// writing buffer to file
if (!std::ofstream(fullFilePath).write(contents, ist.size))
{
return EXIT_FAILURE;
}
Solution:
// writing buffer to file
if (!std::ofstream(fullFilePath, std::ios::binary).write(contents, ist.size))
{
return EXIT_FAILURE;
}
I want to calculate Sha1 of any given file in C++ using OpenSSL library.
I have read any article on the internet (including all from stackoverflow too) about doing this for almost 3 days.
Finally I get my program to work but the generated hash of any given file is not as it should be.
My code is someway similar to these found here and here but more easy to read and to use further in my program I write.
Also, I want to use C++ code not C code as they are written in the links above, second, they use:
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char*)input, length);
SHA256_Final(md, &context);
which aren't available anymore in the new/current OpenSSL version (3.0 or so, I think).
So, I think this question will help many other readers that I observe meet the same problem(s) I do with the new OpenSSL version and can not use old code samples anymore.
This is my C++ code that is created to read huge files by chuncks without loading them into memory (hope this will help future readers of this post because it have many useful lines but it is not fully working as you will see):
bool hashFullFile(const std::string& FilePath, std::string &hashed, std::string &hash_type) {
bool success = false;
EVP_MD_CTX *context = EVP_MD_CTX_new();
//read file by chuncks:
const int BUFFER_SIZE = 1024;
std::vector<char> buffer (BUFFER_SIZE + 1, 0);
// check if the file to read from exists and if so read the file in chunks
std::ifstream fin(FilePath, std::ifstream::binary | std::ifstream::in);
if (hash_type == "SHA1") {
if (context != NULL) {
if (EVP_DigestInit_ex(context, EVP_sha1(), NULL)) {
while (fin.good()){
fin.read(buffer.data(), BUFFER_SIZE);
std::streamsize s = ((fin) ? BUFFER_SIZE : fin.gcount());
buffer[s] = 0;
//convert vector of chars to string:
std::string str(buffer.data());
if (!EVP_DigestUpdate(context, str.c_str(), str.length())) {
fprintf(stderr, "Error while digesting file.\n");
return false;
}
}
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int lengthOfHash = 0;
if (EVP_DigestFinal_ex(context, hash, &lengthOfHash)) {
std::stringstream ss;
for (unsigned int i = 0; i < lengthOfHash; ++i) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int) hash[i];
}
hashed = ss.str();
success = true;
}else{
fprintf(stderr, "Error while finalizing digest.\n");
return false;
}
}else{
fprintf(stderr, "Error while initializing digest context.\n");
return false;
}
EVP_MD_CTX_free(context);
}else{
fprintf(stderr, "Error while creating digest context.\n");
return false;
}
}
fin.close();
return success;
}
And I am using it like this into main function:
std::string myhash;
std::string myhash_type = "SHA1";
hashFullFile(R"(C:\Users\UserName\data.bin)", myhash, myhash_type);
cout<<myhash<<endl;
The problem is that for a given file it calculates hash:
e.g. 169ed28c9796a8065f96c98d205f21ddac11b14e as the hash output but the same file has the hash:
openssl dgst -sha1 data.bin
SHA1(data.bin)= 1927f720a858d0c3b53893695879ae2a7897eedb
generated by Openssl command line and also by any site from the internet.
I can't figure out what am I doing wrong since my code seems to be correct.
Please help.
Thank you very much in advance!
You're missing the finishing calculation on your EVP API attempt. The use of an intermediate string is unnecessary as well. Finally, the function should return the digest as a vector of bytes. let the caller do with that what they want.
Examples using both the EVP API and a BIO chain are shown below.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <array>
#include <vector>
#include <memory>
#include <openssl/evp.h>
#include <openssl/sha.h>
namespace
{
struct Delete
{
void operator()(BIO * p) const
{
BIO_free(p);
}
void operator()(EVP_MD_CTX *p) const
{
EVP_MD_CTX_free(p);
}
};
using BIO_ptr = std::unique_ptr<BIO, Delete>;
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, Delete>;
}
std::vector<uint8_t> hashFileEVP(const std::string &fname, std::string const &mdname = "sha1")
{
// will hold the resulting digest
std::vector<uint8_t> md;
// set this to however big you want the chunk size to be
static constexpr size_t BUFFER_SIZE = 1024;
std::array<char, BUFFER_SIZE> buff;
// get the digest algorithm by name
const EVP_MD *mthd = EVP_get_digestbyname(mdname.c_str());
if (mthd)
{
std::ifstream inp(fname, std::ios::in | std::ios::binary);
if (inp.is_open())
{
EVP_MD_CTX_ptr ctx{EVP_MD_CTX_new()};
EVP_DigestInit_ex(ctx.get(), mthd, nullptr);
while (inp.read(buff.data(), BUFFER_SIZE).gcount() > 0)
EVP_DigestUpdate(ctx.get(), buff.data(), inp.gcount());
// size output vector
unsigned int mdlen = EVP_MD_size(mthd);
md.resize(mdlen);
// general final digest
EVP_DigestFinal_ex(ctx.get(), md.data(), &mdlen);
}
}
return md;
}
std::vector<uint8_t> hashFileBIO(std::string const &fname, std::string const &mdname = "sha1")
{
// the fixed-size read buffer
static constexpr size_t BUFFER_SIZE = 1024;
// will hold the resulting digest
std::vector<uint8_t> md;
// select this however you want.
const EVP_MD *mthd = EVP_get_digestbyname(mdname.c_str());
if (mthd)
{
// open the file and a message digest BIO
BIO_ptr bio_f(BIO_new_file(fname.c_str(), "rb"));
BIO_ptr bio_md(BIO_new(BIO_f_md()));
BIO_set_md(bio_md.get(), mthd);
// chain the bios together. note this bio is NOT
// held together with a smart pointer; all the
// bios in the chain are.
BIO *bio = BIO_push(bio_md.get(), bio_f.get());
// read through file one buffer at a time.
std::array<char, BUFFER_SIZE> buff;
while (BIO_read(bio, buff.data(), buff.size()) > 0)
; // intentionally empty
// size output buffer
unsigned int mdlen = EVP_MD_size(mthd);
md.resize(mdlen);
// read final digest from md bio.
BIO_gets(bio_md.get(), (char *)md.data(), mdlen);
}
return md;
}
// convert a vector of byte to std::string
std::string bin2hex(std::vector<uint8_t> const& bin)
{
std::string res;
size_t len = 0;
if (OPENSSL_buf2hexstr_ex(nullptr, 0, &len, bin.data(), bin.size(), 0) != 0)
{
res.resize(len);
OPENSSL_buf2hexstr_ex(&res[0], len, &len, bin.data(), bin.size(), 0);
}
return res;
}
int main()
{
OpenSSL_add_all_digests();
// i have this on my rig. use whatever you want
// or get the name from argv or some such.
static const char fname[] = "dictionary.txt";
auto md1 = hashFileEVP(fname);
auto md1str = bin2hex(md1);
std::cout << "hashed with EVP API\n";
std::cout << md1str << '\n';
auto md2 = hashFileBIO(fname);
auto md2str = bin2hex(md1);
std::cout << "hashed with BIO chain\n";
std::cout << md2str << '\n';
}
Output
hashed with EVP API
0A97D663ADA2E039FD904846ABC5361291BD2D8E
hashed with BIO chain
0A97D663ADA2E039FD904846ABC5361291BD2D8E
Output from openssl command line
craig#rogue1 % openssl dgst -sha1 dictionary.txt
SHA1(dictionary.txt)= 0a97d663ada2e039fd904846abc5361291bd2d8e
Note the digests are the same in all three cases.
On Windows platform, a file handle is got from calling CreateFile, and then the handle is used to initialize an ofstream object. A minimal example is as below:
#include"stdafx.h"
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
class CSV_writer {
public:
std::ofstream my_ofstream;
private:
HANDLE my_handle = INVALID_HANDLE_VALUE;
int file_descriptor = -1;
FILE * my_file = nullptr; //FILE type is actually a IO buff.
const static unsigned int fl = 256;
public:
explicit CSV_writer(const TCHAR * file_name_) {
//get current directory
TCHAR current_path[MAX_PATH];
GetCurrentDirectory(MAX_PATH, current_path);
TCHAR filename[fl]{ 0 };
_tcscat_s(filename, file_name_);
_tcscat_s(filename, _T(".csv"));
if (current_path[_tcslen(current_path) - 1] != _T('\\') && _tcslen(current_path) < MAX_PATH - 1) {
_tcscat_s(current_path, _T("\\"));
}
else {
throw std::exception("path length exceeding limit.");
}
if (_tcslen(current_path) + _tcslen(filename) + 1 < MAX_PATH) {
_tcscat_s(current_path, filename);
}
else {
//current path exceeds the max path length defined in MAX_PATH
throw std::exception("path length exceeding limit.");
}
this->my_handle = CreateFile(
current_path,
GENERIC_READ | GENERIC_WRITE, //access permit, both read and write
0, //cannot be shared and cannot be opened again until the handle to the file or device is closed
nullptr, //returned handle can not be inherited by child process
CREATE_ALWAYS, //always create a new file, overwrite old one if it exists
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (my_handle != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)my_handle, _O_TEXT);
if (file_descriptor != -1) {
this->my_file = _fdopen(file_descriptor, "w");
if (this->my_file != nullptr) {
this->my_ofstream = std::ofstream(this->my_file);
}
}
}
}
~CSV_writer() {
// Closes stream, file, file_descriptor, and file_handle.
this->my_ofstream.flush();
this->my_ofstream.close();
this->my_file = nullptr;
this->file_descriptor = -1;
this->my_handle = INVALID_HANDLE_VALUE;
}
};
int main(int argc, char* argv[])
{
CSV_writer csv_writer(L"memory_layout");
csv_writer.my_ofstream << "Type,\t" << "Size,\t" << "Offset,\t" << "Address\n";
return 0;
}
My question is, after calling "my_ofstream.close()" afterwards, will the underlying file handle also released? Or I have to call Windows API CloseHandle() manually after calling close()?
Update: to those who say that there is no constructor of ofstream taking FILE*, actually there is, kind of,
I hope you're already aware that the constructor you are using:
std::ofstream(FILE * fp)
is a non-standard, undocumented Microsoft extension, unguaranteed even by Microsoft.
In that case, Microsoft does not promise you even that:
int fd = ...;
...
FILE * fp = _fdopen(fd, "w");
...
std::osftream ofs(fp);
...
ofs.close();
will do fclose(fp) - never mind _close(fd).
If however you take it as given that ofs.close() does fclose(fp) - and evidently you do - then Microsoft
does promise you that it will also _close(fd). From the documentation
Remarks
...
File descriptors passed into _fdopen are owned by the returned FILE * stream.
If _fdopen is successful, do not call _close on the file descriptor.
Calling fclose on the returned FILE * also closes the file descriptor.
(My emphasis.)
I'm trying to read file, which contains Cyrillic characters in their path, and got ifstream.is_open() == false
This is my code:
std::string ReadFile(const std::string &path) {
std::string newLine, fileContent;
std::ifstream in(path.c_str(), std::ios::in);
if (!in.is_open()) {
return std::string("isn't opened");
}
while (in.good()) {
getline(in, newLine);
fileContent += newLine;
}
in.close();
return fileContent;
}
int main() {
std::string path = "C:\\test\\документ.txt";
std::string content = ReadFile(path);
std::cout << content << std::endl;
return 0;
}
Specified file exists
I'm trying to find solution in google, but I got nothing
Here is links, which I saw:
I don't need wstring
The same as previous
no answer here
is not about C++
has no answer too
P.S. I need to get file's content in string, not in wstring
THIS IS ENCODING SETTINGS OF MY IDE (CLION 2017.1)
You'll need an up-to-date compiler or Boost. std::filesystem::path can handle these names, but it's new in the C++17 standard. Your compiler may still have it as std::experimental::filesystem::path, or else you'd use the third-party boost::filesystem::path. The interfaces are pretty comparable as the Boost version served as the inspiration.
The definition for std::string is std::basic_string, so your Cyrillic chararecters are not stored as intended. Atleast, try to use std::wstring to store your file path and then you can read from file using std::string.
First of all, set your project settings to use UTF-8 encoding instead of windows-1251. Until standard library gets really good (not any time soon) you basically can not rely on it if you want to deal with io properly. To make input stream read from files on Windows you need to write your own custom input stream buffer that opens files using 2-byte wide chars or rely on some third-party implementations of such routines. Here is some incomplete (but sufficient for your example) implementation:
// assuming that usual Windows SDK macros such as _UNICODE, WIN32_LEAN_AND_MEAN are defined above
#include <Windows.h>
#include <string>
#include <iostream>
#include <system_error>
#include <memory>
#include <utility>
#include <cstdlib>
#include <cstdio>
static_assert(2 == sizeof(wchar_t), "wchar_t size must be 2 bytes");
using namespace ::std;
class MyStreamBuf final: public streambuf
{
#pragma region Fields
private: ::HANDLE const m_file_handle;
private: char m_buffer; // typically buffer should be much bigger
#pragma endregion
public: explicit
MyStreamBuf(wchar_t const * psz_file_path)
: m_file_handle(::CreateFileW(psz_file_path, FILE_GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))
, m_buffer{}
{
if(INVALID_HANDLE_VALUE == m_file_handle)
{
auto const error_code{::GetLastError()};
throw(system_error(static_cast< int >(error_code), system_category(), "::CreateFileW call failed"));
}
}
public:
~MyStreamBuf(void)
{
auto const closed{::CloseHandle(m_file_handle)};
if(FALSE == closed)
{
auto const error_code{::GetLastError()};
//throw(::std::system_error(static_cast< int >(error_code), system_category(), "::CloseHandle call failed"));
// throwing in destructor is kinda wrong
// but if CloseHandle returned false then our program is in inconsistent state
// and must be terminated anyway
(void) error_code; // not used
abort();
}
}
private: auto
underflow(void) -> int_type override
{
::DWORD bytes_count_to_read{1};
::DWORD read_bytes_count{};
{
auto const succeeded{::ReadFile(m_file_handle, addressof(m_buffer), bytes_count_to_read, addressof(read_bytes_count), nullptr)};
if(FALSE == succeeded)
{
auto const error_code{::GetLastError()};
setg(nullptr, nullptr, nullptr);
throw(system_error(static_cast< int >(error_code), system_category(), "::ReadFile call failed"));
}
}
if(0 == read_bytes_count)
{
setg(nullptr, nullptr, nullptr);
return(EOF);
}
setg(addressof(m_buffer), addressof(m_buffer), addressof(m_buffer) + 1);
return(m_buffer);
}
};
string
MyReadFile(wchar_t const * psz_file_path)
{
istream in(new MyStreamBuf(psz_file_path)); // note that we create normal stream
string new_line;
string file_content;
while(in.good())
{
getline(in, new_line);
file_content += new_line;
}
return(::std::move(file_content));
}
int
main(void)
{
string content = MyReadFile(L"C:\\test\\документ.txt"); // note that path is a wide string
cout << content << endl;
return 0;
}
Change your code to use wstring and save your file using Unicode encoding (non UTF8 one, use USC-2, UTF16 or something like that). MSVC has non-standard overload specifically for this reason to be able to handle non-ascii chars in filenames:
std::string ReadFile(const std::wstring &path)
{
std::string newLine, fileContent;
std::ifstream in(path.c_str(), std::ios::in);
if (!in)
return std::string("isn't opened");
while (getline(in, newLine))
fileContent += newLine;
return fileContent;
}
int main()
{
std::wstring path = L"C:\\test\\документ.txt";
std::string content = ReadFile(path);
std::cout << content << std::endl;
}
Also, note corrected ReadFile code.
I am writing a C++ application and I need to read the result of a system command.
I am using popen() more or less as shown here:
const int MAX_BUFFER = 2048;
string cmd="ls -l";
char buffer[MAX_BUFFER];
FILE *stream = popen(cmd.c_str(), "r");
if (stream){
while (!feof(stream))
{
if (fgets(buffer, MAX_BUFFER, stream) != NULL)
{
//here is all my code
}
}
pclose(stream);
}
I've been trying to re-write this in a different way. I saw some non-standard solutions like:
FILE *myfile;
std::fstream fileStream(myfile);
std::string mystring;
while(std::getline(myfile,mystring))
{
// .... Here I do what I need
}
My compiler does not accept this though.
How can I read from popen in C++?
Your example:
FILE *myfile;
std::fstream fileStream(myfile);
std::string mystring;
while(std::getline(myfile,mystring))
Does't work because although you're very close the standard library doesn't provide an fstream that can be constructed from a FILE*. Boost iostreams does however provide an iostream that can be constructed from a file descriptor and you can get one from a FILE* by calling fileno.
E.g.:
typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink>
boost_stream;
FILE *myfile;
// make sure to popen and it succeeds
boost_stream stream(fileno(myfile));
stream.set_auto_close(false); // https://svn.boost.org/trac/boost/ticket/3517
std::string mystring;
while(std::getline(stream,mystring))
Don't forget to pclose later still.
Note: Newer versions of boost have deprecated the constructor which takes just a fd. Instead you need to pass one of boost::iostreams::never_close_handle or boost::iostreams::close_handle as a mandatory second argument to the constructor.
Here is something which i wrote long back, may help you. It might have some errors.
#include <vector>
#include <string>
#include <stdio.h>
#include <iostream>
bool my_popen (const std::string& cmd,std::vector<std::string>& out ) {
bool ret_boolValue = true;
FILE* fp;
const int SIZEBUF = 1234;
char buf [SIZEBUF];
out = std::vector<std::string> ();
if ((fp = popen(cmd.c_str (), "r")) == NULL) {
return false;
}
std::string cur_string = "";
while (fgets(buf, sizeof (buf), fp)) {
cur_string += buf;
}
out.push_back (cur_string.substr (0, cur_string.size () - 1));
pclose(fp);
return true;
}
int main ( int argc, char **argv) {
std::vector<std::string> output;
my_popen("ls -l > /dev/null ", output);
for ( std::vector<std::string>::iterator itr = output.begin();
itr != output.end();
++itr) {
std::cout << *itr << std::endl;
}
}