Merry Christmas, everyone.
Yesterday I download the Boost library. i use CodeBlocks (with Mingw32 gcc V4.4.1)
to compile it. The bjam command line is :
bjam install --toolset=gcc--prefix="C:\zjc\PluginFramework\boost_1_42_0" --build-type=complete.
and it is successful.
and i want to test the library. i write some code as follow:
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::wcout;
using std::endl;
#include <string>
using std::string;
using std::wstring;
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/format.hpp>
int main(int argc, char* argv[])
{
// ANSI character format
cout << boost::format( "%1% %2%" ) % "Hell" % "Low" <<endl;
string s1 = boost::str( boost::format( "%2% %1%" ) % "Hell" % "Low" );
cout << s1 << endl;
// UNICODE character format
wcout << boost::wformat( L"%s %X" ) % L"-1 is" % -1 << endl;
wstring s2 = boost::str( boost::wformat( L"%2$s %1$.2f" ) % 3.141592 % L"Version" );
wcout << s2 << endl;
// get the path of application(ANSI character set), note:boost::filesystem::path
string AnsiPath = boost::filesystem::initial_path<boost::filesystem::path>().string();
cout<<AnsiPath<<endl;
// get the path of application(unicode character set), note:boost::filesystem::wpath
wstring UnicodePath = boost::filesystem::initial_path<boost::filesystem::wpath>().string();
wcout<<UnicodePath<<endl;
system("PAUSE");
return 0;
}
one compile error occur: obj\Debug\main.o:C:\zjc\PluginFramework\boost_1_42_0\include\boost-1_42\boost\filesystem\operations.hpp|530|undefined reference to `boost::filesystem::detail::get_current_path_api(std::string&)'|
I have added the the library at linker option:
boost_system-mgw44-mt-d-1_42.lib
libboost_system-mgw44-sd-1_42.lib
boost_system-mgw44-d.lib
boost_system-mgw44-d-1_42.lib
boost_system-mgw44-mt-d-1_42.lib
the macros:
BOOST_ALL_DYN_LINK
BOOST_SYSTEM_NO_LIB
BOOST_SYSTEM_NO_DEPRECATED
_DEBUG
_CONSOLE
BOOST_FILESYSTEM_VERSION
BOOST_FILESYSTEM_DYN_LINK
BOOST_LIB_DIAGNOSTIC
I search the internet.the solution is linking the boost filesystem library.but i have linked the library. My Environment: Win 7 Home version, Code::Blocks V 10.05.
The Boost filesystem library is one of the linkable (and not header only) libraries included. Just add "boost_filesystem" before "boost_system".
If everything is set up the right way, you shouldn't have to add the libraries yourself:
Don't set BOOST_SYSTEM_NO_LIB/BOOST_FILESYSTEM_NO_LIB unless you really have to. If it isn't set, the headers should handle the dependencies for you.
The macros with BOOST_..._DYN_LINK will cause the headers to try to link the shared libraries (which you deactivated with the other macros).
Just one more note: If you'd like to add the libs by hand. Don't mix them and only add one variant each, which you need, and pick the right one (e.g. multithreaded debug "mt-d").
Related
I have a russian Roulette script written with C++. If two randomly generated numbers are the same, the script deletes a specified file.
People suggested to me that I should use C++17 for using the <filesystem> library in order to run file-related operations correctly. The removing operation runs if the conditions are matching. The if block runs correctly, but removing the file isn't happening.
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <filesystem>
//include filesystem and replace remove() with filesystem libs remove function
using namespace std;
namespace fs = std::filesystem;
int main(){
int minNumber = 1, maxNumber = 6;
int possibility,chamberNumber;
srand(time(0));
possibility = rand() % (maxNumber - minNumber + 1 ) + minNumber;
chamberNumber = rand() % (maxNumber - minNumber + 1 ) + minNumber;
cout << "First Number: " <<possibility<<endl<<"Second Number: " << chamberNumber<< endl;
if (possibility == chamberNumber){
std::filesystem::remove("C:\\Users\\mypath\\Desktop\\cppRoulette\\delete.txt");
cout << "You're Dead " <<possibility<< endl;
}
// else{
// cout << possibility << endl;
// }
return 0;
}
I use this line to compile my code:
g++ -std=c++17 rulet.cpp -o output
Here is a screenshot of the compiled output. Notice "delete.txt" still stands.
I am using WSL Debian, because I am using VS Code and native terminals don't work proper with g++. I may like smoothness of Linux a bit more, though.
I am looking for a proper and easier way to deal with files, just like in Python. I am attending a C++ crash course, so I am trying to learn it, switching to Python isn't on the table.
Your file path is wrong. I just got your code to work on my system by changing the path from E:\Test\delete.txt to /mnt/e/Test/delete.txt.
Under WSL, all Windows drives (C:, E:, etc.) are mounted under the /mnt directory, in subdirectories that match the drive letter (/mnt/c/, /mnt/e/, etc). In order to convert your Windows path for use in WSL, you need to do the following:
Replace all backslashes (\) with forward slashes (/).
Remove the colon (:) after the drive letter.
Convert the drive letter to lower case.
Prepend the string "/mnt/" to the path.
After this, your program works, and will delete the target file.
I'm creating C++ code that will create some .bat file and store it in the %appdata% folder. I've successfully to created the file, but still fail to create the folder and execute it.
Below is my simple code, it doesn't look simple but it works to create .bat file in %appdata%, maybe someone can help me to find the simple one.
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <string>
#include <windows.h>
#include <direct.h>
int main(int argc, char **argv) {
using namespace std;
std::ofstream aaa;
ostringstream aaa;
aaa.open(aaa1.str());
aaa1 << getenv("appdata") << "/"
<< "test.bat";
aaa.open(aaa1.str());
Updater << "#echo on" << endl;
Updater << "echo \"on\"" << endl;
return 0;
}
The code successfully creates the .bat file in %appdata%, but I need to store in new folder in %appdata%, say New Folder, and then execute the .bat file.
Create Directory
1st get the path using _dupenv_s() in string add new folder name "\New Folder"
2nd Create Directory using _mkdir(str.c_str());
3rd Create "test.bat" using std::ofstream outf(str);
#include "stdafx.h"
#include<fstream>
#include<iostream>
#include<conio.h>
#include<direct.h>
using std::cout;
using std::cin;
using std::endl;
int tmain(int argc, TCHAR* argv[])
{
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
std::string NewFile = "\\new";
std::string str(pValue);
str = str + NewFile;
_mkdir(str.c_str());
str = str + "\\Sample.bat"; //
std::ofstream outf(str);
if (!outf)
{
printf("error ");
}
outf << "this is line1" << endl;
outf << "line 2" << endl;
return 0;
}
Please! Don't Forgot to Vote If its Helps
Creating/running an executable in a user writable location is something to be careful with (exploit people into running your process elevated, then running an attack payload), otherwise just a couple of things to tie together.
On Windows, most of those environment variables exist for legacy / compatibility reasons, SHGetKnownFolderPath is the modern way to find the folders. It allocates enough space for the path, be careful with manual memory from C-API, get it a unique_ptr or wstring as soon as possible. It works from Vista, there are older API's if really needed.
wchar_t *str = nullptr;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &str); // CHECK RETURN
...use str...
CoTaskMemFree(str);
Also be aware of Unicode and spaces in file paths.
Processes have two options, there is the system(command_line) in the cstdlib header, or for advanced use check out the Windows CreateProcessW. Something like:
STARTTUPINFO startup;
startup.cb = sizeof(startup);
PROCESS_INFORMATION pi;
CreateProcessW(NULL, L"cmd.exe /C C:\\ThePath\\myfile.bat", NULL, NULL, FALSE, 0, NULL, NULL, &startup, &pi);
Obviously specific to Windows. Linux, Mac, etc. have their own filesystem layouts and security.
C++ fstream won't create directories for you automatically. You could set up such directories as part of an installer, but to do it at runtime C++17 has std::filesystem::create_directories, which takes a path. If you can't use C++17, use CreateDirectory or _mkdir. Again on Windows be aware of Unicode.
I'm trying to get all files in directory through c++17 on my visual studio 2017 but I've just encountered a really weird problem. If I specify directory like this I can get all files without any problem:
for (auto& p : std::filesystem::recursive_directory_iterator("C:\\Users\\r00t\\AppData\\Roaming\\Mozilla")) {
if (std::filesystem::is_regular_file(p.path())) {
std::cout << p.path() << std::endl;
}
}
But I need all file list on APPDATA, and I'm trying to get path with getenv() function and when using it "recursive_directory_iterator" function skipping files:
for (auto& p : std::filesystem::recursive_directory_iterator(getenv("APPDATA"))) {
if (std::filesystem::is_regular_file(p.path())) {
std::cout << p.path() << std::endl;
}
}
Is that because of using getenv() function? Some folders that skipping when using getenv;
Mozilla
TeamWiever
NVIDIA
and so on ..
Btw, I'm using C++ last 5 days and definitely don't have any clue what causes for that behavior. Please help me, right now I'm stuck.
EDIT :
for (auto& p : std::filesystem::directory_iterator(getenv("APPDATA"))) {
std::string targetFolder = p.path().string();
for (auto& targetFolderFiles : std::filesystem::recursive_directory_iterator(targetFolder)) {
if (std::filesystem::is_regular_file(targetFolderFiles.path())) {
std::cout << targetFolderFiles.path() << std::endl;
}
}
}
This is also not working, seems like i must put string into function like this:
recursive_directory_iterator("C:\\Users\\r00t\\AppData\\Roaming\\Mozilla")
otherwise definitely not working, LOL ??
EDIT - PROBLEM FIXED
Using experimental library is working with C++14 compiler like as expected.
#include <experimental/filesystem>
Now i can able to get all files without problem.Seems like this is problem about C++17 and filesystem library ..
Thanks for all support guys.
getenv() returns a char* or NULL. <filesystem> is probably operating with wchar_t* strings since you are on Windows. Use SHGetKnownFolderPath(...) to query for where special folders are.
What happens when you run your program is probably that you hit some character that can't be displayed with your current locale ("C" if not set explicitly) so it sets your outstream in fail mode. You can however set your locale to UTF-16LE to remedy this. It works with /std:c++17 and the standard <filesystem> header:
#include <Shlobj.h> // SHGetKnownFolderPath
#include <clocale> // std::setlocale
#include <io.h> // _setmode
#include <fcntl.h> // _O_U16TEXT
Code Page Identifiers
const char CP_UTF_16LE[] = ".1200";
setlocale(LC_ALL, CP_UTF_16LE);
_setmode
_setmode(_fileno(stdout), _O_U16TEXT);
With that in place, the path you get from SHGetKnownFolderPath should work:
PWSTR the_path;
if(SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &the_path) == S_OK) {
for(auto& p : std::filesystem::recursive_directory_iterator(the_path)) {
std::wcout << p.path() << L"\n";
// you can also detect if the outstream is in fail mode:
if (std::wcout.fail()) {
std::wcout.clear(); // ... and clear the fail mode
std::wcout << L" (wcout was fail mode)\n";
}
}
CoTaskMemFree(the_path);
}
You may also find the list of Default Known Folders in Windows useful.
I want to use Boost's filesystem functions. I try
cout << boost::filesystem::file_size(fname.c_str()) << endl;
where fname="file.txt"; and I get the error
boost::filesystem::file_size: No such file or directory
I am sure I have the right path because system("cat file.txt") works. I checked that the folder is not NFS; it is NTFS.
I am using g++ on cygwin on a Windows 7 machine.
EDIT: I also tried
cout << boost::filesystem::file_size(fname);
and using fname="./file.txt"
In the makefile I'm linking using -lboost_system -lboost_filesystem and also using -I /usr/local/opt/boost/include -L /usr/local/opt/boost/lib
UPDATE: I changed it so there is a using namespace boost::filesystem; at the beginning of the file and removed boost::filesystem::" in front of file_size(). Now I have the same error using fname="file.txt" but if I use fname="./file.txt" I get a new error:
boost::filesystem::file_size: Operation not permitted
I have tried different kinds of files (.txt, .dat, .cpp)
The tutorial program tut1.cpp that comes with it and uses the same syntax works, so I'm thinking it could be a compiling problem. I have tried to find the file (presumably a makefile) compiling tut1.cpp with no luck.
tut1.cpp looks like this:
// filesystem tut1.cpp ---------------------------------------------------------------//
// Copyright Beman Dawes 2009
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
// Library home page: http://www.boost.org/libs/filesystem
#include <iostream>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cout << "Usage: tut1 path\n";
return 1;
}
std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
return 0;
}
Is fname a path? Because, then, just drop the .c_str() member invocation.
It might be that the accessor functions add some Operating System Specific quoting or escaping. (example on linux)
You might assign to a std::string so you can observe the value in a debugger.
In C++, I want to use Unicode to do things. So after falling down the rabbit hole of Unicode, I've managed to end up in a train wreck of confusion, headaches and locales.
But in Boost I've had the unfortunate problem of trying to use Unicode file paths and trying to use the Boost program options library with Unicode input. I've read whatever I could find on the subjects of locales, codecvts, Unicode encodings and Boost.
My current attempt to get things to work is to have a codecvt that takes a UTF-8 string and converts it to the platform's encoding (UTF-8 on POSIX, UTF-16 on Windows), I've been trying to avoid wchar_t.
The closest I've actually gotten is trying to do this with Boost.Locale, to convert from a UTF-8 string to a UTF-32 string on output.
#include <string>
#include <boost/locale.hpp>
#include <locale>
int main(void)
{
std::string data("Testing, 㤹");
std::locale fromLoc = boost::locale::generator().generate("en_US.UTF-8");
std::locale toLoc = boost::locale::generator().generate("en_US.UTF-32");
typedef std::codecvt<wchar_t, char, mbstate_t> cvtType;
cvtType const* toCvt = &std::use_facet<cvtType>(toLoc);
std::locale convLoc = std::locale(fromLoc, toCvt);
std::cout.imbue(convLoc);
std::cout << data << std::endl;
// Output is unconverted -- what?
return 0;
}
I think I had some other kind of conversion working using wide characters, but I really don't know what I'm even doing. I don't know what the right tool for the job is at this point. Help?
Okay, after a long few months I've figured it out, and I'd like to help people in the future.
First of all, the codecvt thing was the wrong way of doing it. Boost.Locale provides a simple way of converting between character sets in its boost::locale::conv namespace. Here's one example (there's others not based on locales).
#include <boost/locale.hpp>
namespace loc = boost::locale;
int main(void)
{
loc::generator gen;
std::locale blah = gen.generate("en_US.utf-32");
std::string UTF8String = "Tésting!";
// from_utf will also work with wide strings as it uses the character size
// to detect the encoding.
std::string converted = loc::conv::from_utf(UTF8String, blah);
// Outputs a UTF-32 string.
std::cout << converted << std::endl;
return 0;
}
As you can see, if you replace the "en_US.utf-32" with "" it'll output in the user's locale.
I still don't know how to make std::cout do this all the time, but the translate() function of Boost.Locale outputs in the user's locale.
As for the filesystem using UTF-8 strings cross platform, it seems that that's possible, here's a link to how to do it.
std::cout.imbue(convLoc);
std::cout << data << std::endl;
This does no conversion, since it uses codecvt<char, char, mbstate_t> which is a no-op. The only standard streams that use codecvt are file-streams. std::cout is not required to perform any conversion at all.
To force Boost.Filesystem to interpret narrow-strings as UTF-8 on windows, use boost::filesystem::imbue with a locale with a UTF-8 ↔ UTF-16 codecvt facet. Boost.Locale has an implementation of the latter.
The Boost filesystem iostream replacement classes work fine with UTF-16 when used with Visual C++.
However, they do not work (in the sense of supporting arbitrary filenames) when used with g++ in Windows - at least as of Boost version 1.47. There is a code comment explaining that; essentially, the Visual C++ standard library provides non-standard wchar_t based constructors that Boost filesystem classes make use of, but g++ does not support these extensions.
A workaround is to use 8.3 short filenames, but this solution is a bit brittle since with old Windows versions the user can turn off automatic generation of short filenames.
Example code for using Boost filesystem in Windows:
#include "CmdLineArgs.h" // CmdLineArgs
#include "throwx.h" // throwX, hopefully
#include "string_conversions.h" // ansiOrFillerFrom( wstring )
#include <boost/filesystem/fstream.hpp> // boost::filesystem::ifstream
#include <iostream> // std::cout, std::cerr, std::endl
#include <stdexcept> // std::runtime_error, std::exception
#include <string> // std::string
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
using namespace std;
namespace bfs = boost::filesystem;
inline string ansi( wstring const& ws ) { return ansiWithFillersFrom( ws ); }
int main()
{
try
{
CmdLineArgs const args;
wstring const programPath = args.at( 0 );
hopefully( args.nArgs() == 2 )
|| throwX( "Usage: " + ansi( programPath ) + " FILENAME" );
wstring const filePath = args.at( 1 );
bfs::ifstream stream( filePath ); // Nice Boost ifstream subclass.
hopefully( !stream.fail() )
|| throwX( "Failed to open file '" + ansi( filePath ) + "'" );
string line;
while( getline( stream, line ) )
{
cout << line << endl;
}
hopefully( stream.eof() )
|| throwX( "Failed to list contents of file '" + ansi( filePath ) + "'" );
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}