How do I create a file if the file does not exist? - c++11

I am currently trying to create a file after trying to open it, if it does not exist.
I would like to do this without the use of ios::app because with this, I would not be able to use the seek function in the future.
My includes:
#include <string>
#include <errno.h>
#include <fstream>
#inlcude <iostream>
using namespace std;
My main:
string str;
cout << "Enter a string: " << endl;
cin >> str;
fstream fstr;
fstr.open("test.txt", ios::in | ios::out | ios::binary | ios::ate );
if (fstr.fail()) {
cerr << strerror(errno) << endl;
fstr.open("test.txt", ios::out);
fstr.close();
fstr.open("test.txt", ios::in | ios::out | ios::binary | ios::ate );
} // if file does not exist, create by using "ios::out",close it, then re-open for my purpose
if (fstr.is_open()) { // if the file opens/exists
fstr << str << endl; // str goes into fstr
fstr.close(); // close
}
The code above seems to be working fine, but I just wanted to be open for any other advice, other suggestions or alternate methods of achieving the same goal. Thanks!

As an alternative, you could use the stat() function, which is available on Unix based systems and also Windows. Then you could write a very simple function that test if a filename exists and names a file:
#include <sys/stat.h>
bool FileExistAndIsFile(const std::string & filePath)
{
int result;
struct stat statBuf;
result = stat(filePath.c_str(), &statBuf);
return ((result == 0) && S_ISREG(statBuf.st_mode)) ? true : false;
}

Related

How to Convert Custom string to ptime using boost

I have a string "2018Jan23T181138.65498648" which I need to convert to ptime. I have used below code but seems it is not working. Any idea what I am doing wrong here.
boost::posix_time::ptime pt;
std::istringstream is("2018Jan23T181138.65498648");
is.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y%m%dT%H%M%S.%f")));
is >> pt;
std::cout << pt;
You need to at least match the format string to reflect the input format.
"Jan" is not a valid match for %Y%m%d (which would expect 20180123 instead). Likewise, %S.%f is a format string that might work for formatting¹, but to parse the seconds with fractions, the docs show to use %s
Live On Coliru
#include <boost/date_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <sstream>
#include <iostream>
int main() {
boost::posix_time::ptime pt;
std::istringstream is("2018Jan23T181138.65498648");
is.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y%b%dT%H%M%s")));
if (is >> pt) {
std::cout << pt << "\n";
} else {
std::cout << "unparsed\n";
}
}
Prints
2018-Jan-23 18:11:38.654986
¹ haven't tested it for output formatting

serialize temporary into boost archive

The following is not possible for any boost output archive:
int foo(){
return 4;
}
ar << static_cast<unsigned int>(foo());
Is there an alternative without out creating a local temporary x=foo().
and why is the underlying archive operator <<(T & t) not const reference , for an output archive such that the above would work?
This seems to work, and I think this is why:
... To help detect such cases, output archive operators expect to be
passed const reference arguments.
It seems worth noting that in your example ar << foo(); does not work either (i.e. it doesn't have to do with your cast).
#include <fstream>
#include <iostream>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
unsigned int foo(){
return 4;
}
int main()
{
{
std::ofstream outputStream("someFile.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << static_cast<const int&>(foo());
}
std::ifstream inputStream("someFile.txt");
boost::archive::text_iarchive inputArchive(inputStream);
int readBack;
inputArchive >> readBack;
std::cout << "Read back: " << readBack << std::endl;
return 0;
}

Move or swap a stringstream

I want to move a stringstream, in the real world application I have some stringstream class data member, which I want to reuse for different string's during operation.
stringstream does not have a copy-assignment or copy constructor, which makes sense. However, according to cppreference.com and cplusplus.com std::stringstream should have a move assignment and swap operation defined. I tried both, and both fail.
Move assignment
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream stream("1234");
//stream = std::move(std::stringstream("5678"));
stream.operator=(std::move(std::stringstream("5678")));
//stream.operator=(std::stringstream("5678"));
return 0;
}
source: http://ideone.com/Izyanb
prog.cpp:11:56: error: use of deleted function ‘std::basic_stringstream<char>& std::basic_stringstream<char>::operator=(const std::basic_stringstream<char>&)’
stream.operator=(std::move(std::stringstream("5678")));
The compiler states that there is no copy assignment for all three statements, which is true. However, I fail to see why it is not using the move-assignment, especially since std::move is supposed to return a rvalue reference. Stringstream should have a move assignment, as shown here: http://en.cppreference.com/w/cpp/io/basic_stringstream/operator%3D
PS: I'm working with c++11, hence rvalue-references are part of the 'world'.
Swap
This I found really strange, I copied example code from cplusplus.com and it failed:
// swapping stringstream objects
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream foo;
std::stringstream bar;
foo << 100;
bar << 200;
foo.swap(bar);
int val;
foo >> val; std::cout << "foo: " << val << '\n';
bar >> val; std::cout << "bar: " << val << '\n';
return 0;
}
source: http://ideone.com/NI0xMS
cplusplus.com source: http://www.cplusplus.com/reference/sstream/stringstream/swap/
prog.cpp: In function ‘int main()’:
prog.cpp:14:7: error: ‘std::stringstream’ has no member named ‘swap’
foo.swap(bar);
What am I missing? Why can't I move or swap a stringstream? How should I swap or move a stringstream?
This is a missing feature on GCC : see bug 54316 , it has been fixed (you can thank Jonathan Wakely) for the next versions (gcc 5)
Clang with libc++ compiles this code :
int main () {
std::stringstream stream("1234");
std::stringstream stream2 = std::move(std::stringstream("5678"));
return 0;
}
Live demo
And it also compiles the example with std::stringstream::swap
I have an alternative to moving or swapping, one can also clear and set a stringstream to a new string:
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream ss("1234");
ss.clear();
ss.str("5678");
int val;
ss >> val; std::cout << "val: " << val << '\n';
return 0;
}
It's a clean work around that does not require one to refactor code, except for the localized section where the swap is changed to a clear() and str().

How to write UNIX file-system "ls -R /" utility using modern C++11/C++14/C+1Z?

To learn/understand the various concepts of modern C++, I tried to write similar program like "ls -R /" which would recursively lists sub directories. To achieve this I am using the future C++ TS filesystem library so that program could be portable. So far I am able to write the below program to achieve this.
#include<filesystem>
//Other herader files
// Below typedef is for VS2013
using fspath = std::tr2::sys::path;
using dir_iterator = std::tr2::sys::directory_iterator;
using namespace std::tr2::sys;
struct directory {
std::vector<fspath> files;
std::vector<fspath> operator()(const fspath& input) {
std::cout << "Input Directory Name: " << input.string() << std::endl;
dir_iterator bgnitr(input);
dir_iterator enditr;
for (dir_iterator itr = bgnitr; itr != enditr; ++itr) {
// Only store the directory from input directory,
// otherwise display the name
fspath tmp = *itr;
if (is_directory(tmp)) {
files.push_back(tmp);
}
else {
tmp = tmp.filename();
std::cout << tmp.string() << std::endl;
}
}
return files;
}
};
int main(int argc, const char** argv) {
fspath input{argv[1]};
directory dir;
auto files = dir(input);
std::sort(std::begin(files), std::end(files));
std::for_each(std::begin(files), std::end(files), directory());
return 0;
}
The above program works fine and produce the expected result if my input directory has one level of sub-directory. I could have used the "recursive_directory_iterator", but it gives the list of all files within all directory inside the input directory.
It does not handle the scenario where actual input directory contains the sub-directory which itself contains sub-directory and files. Basically these level can be upto any level which gets handled by UNIX "ls -R " utility.
Question
I would like to know that whats could be next approach to handle the n level of hierarchy in the directory?
In general whats sort of approaches we should follow when we need to model/design similar things where "part-whole hierarchies(recursive)" needs to model. I am little bit aware about the "composite design pattern" which can be used to model such stuff. Could this pattern be applied in this particular problem?. If yes, could someone provide explanation/comment?
My main intention over here is to understand general guideline to handle such problem using modern C++ concepts/library/design concepts.Kindly let me know in case someone require any information on this.
I would rename your directory class, it doesn't model a directory, it is a function that prints the contents of a directory.
You can use a range-based for loop with a directory_iterator to make the syntax simpler:
for (auto f : fs::directory_iterator{dir})
Your program assumes it will only be called with a single argument that refers to a directory, whereas ls -R can be called with zero or more arguments that are files or directories.
I would do it like this, although this could probably be improved to simplify the logic in main and incorporate it into the ls function:
#include <utility>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
void ls(std::ostream& out, const fs::path& dir)
{
std::vector<std::pair<std::string, bool>> files;
for (auto f : fs::directory_iterator{dir})
files.emplace_back(f.path().filename(), is_directory(f));
std::sort(files.begin(), files.end());
// print directory contents
out << dir.string() << ":\n";
for (auto& f : files)
out << f.first << '\n';
out << std::endl;
// recurse into directories
for (auto& f : files)
if (f.second)
ls(out, dir / f.first);
}
int main(int argc, char** argv)
{
if (argc < 2)
ls(std::cout, ".");
else
{
std::vector<std::string> files;
std::vector<std::string> dirs;
for (int i = 1; i < argc; ++i)
if (fs::is_directory(argv[i]))
dirs.push_back(argv[i]);
else
files.push_back(argv[i]);
std::sort(files.begin(), files.end());
for (auto& f : files)
std::cout << f << '\n';
std::cout << '\n';
std::sort(dirs.begin(), dirs.end());
for (auto& d : dirs)
ls(std::cout, d);
}
}

Retrieving VolumeDetails of WINDOWS Drives - stuck with 'char []' to 'LPCWSTR' conversion

I am trying to get the VolumeDetails of my WINDOWS system- Drive label plus its respective Volume Serial number. I've tried since an hour and built a code which gone wrong in syntax. At present I am getting the following error with it-
error C2664: 'GetVolumeInformationW' : cannot convert parameter 1 from 'char []' to 'LPCWSTR'
Here is my code:
// getVolDrive.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <direct.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <sstream>
#include <string>
#include <ctype.h>
#include <algorithm>
using namespace std;
//wchar_t mydrives[5];// = " A: ";
char mydrives[] = " A: ";
string retVolSno(char drives[]) //wchar_t drives[]
{
DWORD dwSerial;
stringstream ss;
cout<<drives<<endl;
if(!GetVolumeInformation(drives, NULL, 0, &dwSerial, NULL, NULL, NULL, 0))
{
ss<<"Error: "<<GetLastError();
}
else
{
ss<<hex<<dwSerial;
}
return ss.str();
}
int _tmain(int argc, _TCHAR* argv[])
{
string cVolSno;
ULONG DriveMask = _getdrives();
if(DriveMask == 0)
printf("_getdrives() failed with failure code: %d\n", GetLastError());
else
{
printf("This machine has the following logical drives:\n");
while (DriveMask)
{
cout << "In While" << endl;
if(DriveMask & 1)
printf("%s", mydrives);
wcout << mydrives << endl;
cVolSno = retVolSno(mydrives);
cout<<cVolSno<<endl;
++mydrives[1];
DriveMask >>= 1;
}
}
//std::transform(cVolSno.begin(), cVolSno.end(),cVolSno.begin(), ::toupper);
//cout<<cVolSno<<endl;
_getch();
return 0;
}
I've also tried replacing char with wchar_t, I didn't got any build errors, but while executing the application, got Error Code 3- Path not found!.
CODE MODIFIED:
// getVolDrive.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <direct.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <sstream>
#include <string>
#include <ctype.h>
#include <algorithm>
using namespace std;
//wchar_t mydrives[5];// = " A: ";
char mydrives[] = " A:\\\\ ";
string retVolSno(char drives[]) //wchar_t drives[]
{
DWORD dwSerial;
stringstream ss;
wchar_t text[10];
mbstowcs(text,drives,100); //strlen(drives)+1
LPWSTR ptr = text;
if(!GetVolumeInformation(ptr, NULL, 0, &dwSerial, NULL, NULL, NULL, 0))
{
ss<<"Error: "<<GetLastError();
}
else
{
ss<<hex<<dwSerial;
}
return ss.str();
}
int _tmain(int argc, _TCHAR* argv[])
{
string cVolSno;
ULONG DriveMask = _getdrives();
if(DriveMask == 0)
printf("_getdrives() failed with failure code: %d\n", GetLastError());
else
{
printf("This machine has the following logical drives:\n");
while (DriveMask)
{
if(DriveMask & 1)
printf("%s \n", mydrives);
cVolSno = retVolSno(mydrives);
std::transform(cVolSno.begin(), cVolSno.end(),cVolSno.begin(), ::toupper);
cout<<cVolSno<<endl;
++mydrives[1];
DriveMask >>= 1;
}
}
//std::transform(cVolSno.begin(), cVolSno.end(),cVolSno.begin(), ::toupper);
//cout<<cVolSno<<endl;
_getch();
return 0;
}
OUTPUT:
This machine has the following logical drives:
ERROR: 123
ERROR: 123
C:\\
ERROR: 123
D:\\
ERROR: 123
E:\\
ERROR: 123
I see at least these main issues:
1) wchar_t is the right type because you're compiling for UNICODE, you can write generic code using TCHAR macro or explicitly declare your buffer as wchar_t but that's what to do.
2) You have that error because you're passing wrong path to GetVolumeInformation() (trailing backslash is required so A: must become A:\).
Moreover please note that you have a little bit more easy way to achieve same result, you can use GetLogicalDriveStrings() to directly get a NULL delimited string list. Split it using, for example, this (don't forget UNICODE) and use c_str() with each entry.
EDIT about your modified code:
Why you drive path is A:\\ (escaped to A:\\\\)? Just one trailing backslash is needed so mydrives has to be declared as:
wchar_t mydrives[] = L"A:\\";
EDIT 2: there are more errors in your code so I'll post a reviewed version. There are more things I'd change but I'll point out just what doesn't actually work.
Function retVolSno to read volume serial number. Original version were almost right, in your modified version you perform useless character conversion. What you had to do was just to accept a wchar_t drive path.
Global variable mydrives. You actually don't need any global variable for that. It must be wchar_t and space before/after path are useless. One trailing backslash is needed. Line where you increment character value (++mydrives[0];) must be changed accordingly (index 0 instead of 1).
Check for drive availability. After if(DriveMask & 1) you did forget { then you won't print drive name but you'll perform GetVolumeInformation() even on unavailable drives (error 123). That's why indentation is important...
You're mixing UNICODE/NOT UNICODE and C/C++ stuff. I strongly suggest you pick one of them and you keep it (C or C++? UNICODE or NOT UNICODE?). For example you used C function printf() to print stuff and you have both std::string and wchar_t things.
Let's put everything together to have a working version. First the function to read serial number given drive path:
wstring getVolumeSerialNumber(const wchar_t* drivePath)
{
DWORD dwSerial;
wstringstream ss;
if (!GetVolumeInformation(drivePath, NULL, 0, &dwSerial, NULL, NULL, NULL, 0))
ss << L"Error: " << GetLastError();
else
ss << hex << dwSerial;
return ss.str();
}
It's almost the same as your original version, just changed to work with UNICODE characters. Then main function that cycles through available drives and print out their serial number:
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t drive[] = L"A:\\";
ULONG driveMask = _getdrives();
if (driveMask == 0)
wcout << L"_getdrives() failed with failure code: " << GetLastError() << endl;
else
{
wcout << L"This machine has the following logical drives:" << endl;
while (driveMask)
{
if (driveMask & 1)
{
wcout << drive << endl;
wcout << getVolumeSerialNumber(drive) << endl;
}
++drive[0];
driveMask >>= 1;
}
}
wcin.ignore();
return 0;
}
From the documentation , the first parameters should be with trailing slash if drive letter is passed.
lpRootPathName [in, optional]
A pointer to a string that contains the root directory of the volume to be described.
If this parameter is NULL, the root of the current directory is used.
A trailing backslash is required.
For example, you specify \\MyServer\MyShare as \\MyServer\MyShare\, or the C drive as C:\

Resources