How to name text file at a certain directory? - c++

Ok thanks for the answer Wug! I changed my code but now it's complaining about:
no matching function for call to
std::basic_ofstream::basic_ofstream(std::basic_string)
I'm not sure it makes any difference but i'll just post all of my code it's not that much so far.
I'll try to keep it cleaner from now on.
#include <iostream>
#include <windows.h>
#include <direct.h>
#include <fstream>
using namespace std;
int main()
{ /*Introduction*/
SetConsoleTitle("Journal");
string action, prom0, filename, filepath;
filepath = "C:\\Users\\-\\Desktop\\Projects\\Journal Project\\Logs\\";
cout << "Hi and welcome to Journal! \nHere you can write down your day.\nWrite help for";
cout << "more \nType command to start: ";
/*Choose Action*/
cin >> action;
if (action == "new")
{system("cls");
/*Make new Journal file*/
cout << "Filename: ";
getline(cin, filename);
mkdir("C:\\Users\\-\\Desktop\\Projects\\Journal Project\\Logs");
ofstream journallogs(filepath + filename);
journallogs.close();
}
else {
cout << "Wrong command\n";
};
return 0;}

There are 2 things wrong. The first is what the compiler's complaining about:
ofstream journallogs("C:\\Users\\-\\Desktop\\Projects\\Journal Project\\Logs\\" + getline(cin, filename), ios::out);
std::getline(istream&, string&) returns istream&, and you can't add char * to istream. I recommend taking a look at the documentation for getline(), which might help you understand better how you're supposed to use it. Here's an example anyway:
string filepath = "C:\\Users\\-\\Desktop\\Projects\\Journal Project\\Logs\\";
string filename;
getline(cin, filename);
ofstream journallogs(filepath + filename);
The second problem is that you're reading from cin into filename before calling getline(). When you call getline(), any contents of filename are dropped, so you'll effectively trim the first word off of your filename, which probably isn't what you want. To fix that, remove the extraneous cin >> filename;
Note: indentation is important and helps you read your own code. Put forth the effort to keep your code looking nice.

First, learn this:
Start small and simple.
Add complexity a little at a time.
Test at every step.
develop new functionality in isolation.
Never add to code that doesn't work.
For the rest, I don't use Windows, so I can't be certain my code will work there, but the approach will.
You are trying to 1) get a filename from the user, 2) modify it and then 3) use it to open a file; we will develop these three things in isolation.
Getting a filename from the user. Civilized filenames do not contain whitespace, so they can be read with cin, but if you want to allow whitespace you can use getline instead. Either way, test it.
Modifying the filename. Write code that assigns a value to the filename, just as it does to the path-- do not get the filename from the user, it slows down your testing and is not proper isolation. Now try to append them. If you try filepath + filename, you may get a compiler error. Here's where you must understand the difference between std::string and char[]. A char[] is an array of char, and it (usually) contains a null-terminated sequence of characters; you must read up on arrays and pointers. It is a primitive type, and you cannot simply concatenate two of them with '+', you must use something like strcat, which is dangerous if you haven't done your homework on arrays. On the other hand, std::string is more sophisticated, and can handle '+' and many other operations. If you have a std::string x and you decide you want a char[] after all, you can get one like so: x.c_str().
Opening the file. If I remember right, the ofstream constructor can take a char[], but not a std::string. Test this with a hard-coded string (isolation!).
Once you have these three components working independently, you can hook them together.

Related

C++ reading/writing to two different files (need help understanding which syntax to use)

I'm currently working on this program for a class in my university. I've tried multiple approach with no success. I'm pretty sure it's just a conversion problem, but I want to understand the differences.
What the program supposed to do : We're to create a program that ask the user for two filenames. One will be an input and another will be an output. The program is supposed to read the input and write the line to the output while until the end of the input file is not reached.
My Code :
#include <iostream>
#include <fstream> //included for read/writing files
#include <string> //Included this for getline to read the file
using namespace std;
int main() {
ifstream infile; // Stream to read from input file
ofstream outfile; // Stream to write to output file
char inputfilename[80], outputfilename[80]; //declaring two character arrays to save the file names.
string text;
cout << "What is the name of your input file (text.txt)" ; // Prompting user for input file name
cin >> (inputfilename); // Getting input file
infile.open(inputfilename, ios::in); // Opening the input file.
cout << "What is the name of your output file" ; // Prompting user for output file name
cin >> (outputfilename);
outfile.open(outputfilename, ios::out);
if(!infile) { // If cannot open file
cout << "There was an error opening your file!" ;
return 1;
}
if (!outfile) {
cout << "There was an error opening your file!" ;
return 1;
}
while (infile.eof()==0) {
fgets(text, 80, infile);
fprintf(outfile,"%d. %s\n", text);
}
infile.close(); // Closing input file
outfile.close(); // Closing output file
return 0;
}
What I've tried : I didn't know if it was being affected by how I opened the file. I previously tried.
ifstream infile;
ofstream outfile;
char text, inputfilename[80], outputfilename[80]; <----- 1
cout << "What is the name of your input file (text.txt)" ;
gets(inputfilename); <----- 2
infile.open(inputfilename);
cout << "What is the name of your output file" ;
gets(outputfilename); <----- 2
outfile.open(outputfilename);
1) I switched char I previous tried
char text
char text[80]
char *text[80]
2) Would switching how getting the file name change anything in the while loop(I previous tried getline and gets)? Additionally the "f" in front of fgets/fprints/etc are always associated with a file stream?
Note: My teacher gave us the hint.
"Suppose you read a line from the input file into a string variable called str using the following statement: fgets(str, 80, infile);You can add a line number and save the line with the line number to the output file using the same statement using: fprintf(outfile,"%d. %s\n",Next_line_number++, str);"
from this I tried :
while (infile.eof()==0) {
fgets(text, 80, infile);
fprintf(outfile,"%d. %s\n", text);
}
as well as
while (infile.eof()==0) {
fgets(text, 80, infile);
fputs(text, outFile);
}
and
while (infile.eof()==0) {
getline(infile, text);
fprintf(outfile,"%d. %s\n", text);
}
I also tried making a long and using that to increment the line number. I'm fairly new to programming; if any of the methods I'm using our dated please let me know (on some sites they were saying fgets is dated and not supported on cx11 or some version of C++)! I want to understand the concepts vs just get the programming running. Should note Lines 34-35 are where my code is always erroring out and it's
cannot convert 'std::__cxx11::string {aka std::__cxx11::basic_string}' to 'char*' for argument '1' to 'char* fgets(char*, int, FILE*)'
I figured I was getting this because it has a pointer to the file and I'm asking the user vs having the file declared in the program. This is causing a conversion that causing my error.
fgets(text, 80, infile);
fgets() is a C library function, that expects a char * as its first parameter. It knows absolutely nothing about any C++ class, and not just std::string that you are passing as the first parameter. Neither does fgets() has any clue about the C++ std::ifstream class you're attempting to pass to it as its third parameter. And that's exactly what your compiler's error message states.
You are randomly mixing up C and C++ code, which results in repeated confusion.
char inputfilename[80], outputfilename[80];
You should also use std::strings, instead of arbitrary-sized C style arrays, here.
while (infile.eof()==0) {
This is always a bug, and read this linked article for more information.
fprintf(outfile,"%d. %s\n", text);
Again: fprintf is also a C library function, that knows absolutely nothing about C++ classes like std::string and std::ofstream. In either case, this is a bug because this string has placeholders for two parameters, an integer, %d, and C style string, %s; and you're giving just one parameter here, text. In the event that you were writing C instead of C++ code, this would not've worked either, but that's mostly academic. This is a C++ program, and this C library function has no business doing anything here, in the first place.
When you are reading from a std::ifstream:
You can use std::getline to read an entire line of text into a std::string
Alternatively you can use the >> formatted extraction operator
Or you can use various methods of the std::ifstream object to read from the file and into a suitable buffer
These alternatives are not equivalent (otherwise what would be the point?) and they do different things, and the right one to use depends on what the requirements are.
Similarly, to write to a std::ofstream you can use:
The << formatted output operator.
Various methods of the std::ofstream object itself.
And, in some advanced situations you can take advantage of the iterator library, and implement reading and writing using input and output iterators, too.
The correct approach depends on the individual situation. For more information on how to read and write from files in C++ using these approaches, see any good C++ book. Whichever C++ book actually advised you to use fgets() to read from a std::ifstream and into a std::string: throw it away, and get a better book, from the list linked above. If this is just what you found in some program somewhere on the Internet -- you can't learn C++ this way, by piecing together different parts of different programs, and hope that the results work. To fix all of your compilation errors: remove all that C code that knows absolutely nothing about C++, and replace it with proper C++ code, using any of the options I outlined above, using the examples from the C++ books linked above, as a reference.

How can I open a file based on a file name specified by user input?

I want to make a simple program that will allow the user to create/open files and add text to them. This is the code I have currently:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
cout << "Enter file name:" << endl;
char fileName;
cin >> fileName;
ofstream myFile;
myFile.open(fileName, ios::out);
myFile << "This is the file text.\n";
myFile.close();
return 0;
}
I receive the following error at myFile.open(fileName, ios::out):
error: no matching function for call to 'std::basic_ofstream<char>::open(std::__cxx11::string&, const openmode&)'
The simple problem you are having here is that the variable filename that stores the name of the file is of type char. Change it to string so that it works.
On another note, try to break down the error message you got:
no matching function for call to 'std::basic_ofstream::open(std::__cxx11::string&, const openmode&)'
In open(std::__cxx11::string& ... it clearly says that the data type of the file name should be string&. This indicated that you had a data type error, which is true because you have used char instead of string.
Another thing: use char only when you want to accept a single letter as input; when you want to take a word or a sentence, store it in a string variable, and get it from the user using the getline() function. This will make your life easier.
To modify your code, firstly change your variable declaration statement to:
string fileName; // std:: is not required as you have the line "using namespace std"
Secondly, change the input statement of the file name from cin >> filename; to:
getline(cin, fileName);
It should work after these changes.
EDIT: I found the peoblem to your question. You will nave to change the open command to:
myFile.open(fileName.c_str(), ios::out);
Like it says in the error, the function needs a string passed to ot, however, when we take the string as input and store it in the variable fileName, it simply converts the string into a const char *. This is invisible to you when you run the code, but every once in a while, it causes an error.
This should definitely work now.
If you take a look at the error message, the first half of what is in the open parentheses tells you the answer. The user is typing in a char, the file name is expected to be a string. Instead of:
char fileName;
Use:
string fileName;

.txt file to an array of structures in C++?

I have previously used C++, but I can definitely say I am not a pro. Not really even at coding in general. I'm trying, as much as it may not look like it. :/
My task is to create an array of structres of the type, "book_list".
the struct looks like this:
struct book_list
{
int bookNumber; string bookTitle; string bookAuthor;
string bookDescription; int bookMonth; int bookYear; int bookRating;
};
It's easy enough to create the array itself:
book_list myBookList[50];
Here's where I'm having trouble:
The program is intended to search for a .txt file. If it finds it, it will read into the array of structures all the data contained within the file. So, bookNumber with the .txt file's bookNumber, etc.
I have been looking up potential solutions all day, and I've looked into ideas such as ifstream, getline, using iterators, etc. My research has been as scattered as my brain, and I think I am a little stumped.
Please help, and if you need any further info, please let me know!
Thanks,
-Jon
You need to either read/parse each entry separately or read the entire file in then parse it. Since you're storing all the structs in memory anyway, the latter is probably fine if you don't want to bother with reading one at a time, but for educational purposes, you might want to try reading one at a time. Maybe separate by lines?
Then you need a way to parse the entries. There's no one way to do this, but the easiest is probably to use a JSON-formatted text file, mainly because there are libraries that can use it and tools that can help visualize it. JSON lets you represent dictionaries, arrays, strings, numbers, and booleans. You can either do this manually without much effort since you don't have anything fancy like nested structures, or you can use a library like this to parse JSON for you: https://github.com/DaveGamble/cJSON
(which is in C, will have to link with C++ if you want to use C++)
Assuming that the question may be formulated as:
can you give me a tiny programming example that can kickstart my exercise:
program p:
#include <iostream>
using namespace std;
int main() {
int num;
string buf;
while (true) {
cin >> num; if (cin.eof()) break;
cin >> buf; if (cin.eof()) break;
cout << "num is: " << num << " buf is: " << buf << endl;
}
}
text file t.txt
1
one
2
two
you can run
p < t.txt
and see that the output is what you probably expected.
Now of course change cin >> num; into cin >> booklist[0].bookNumber; etc. and your exercise will be on the right track.
Use <stdio.h> for FILE.
char *name;
FILE *file;
name = "database.txt";
file = fopen(name,"w+");
book_list myBookList[50];
While writing use this.
book_list newRecord;
newRecord.bookNumber = 0;
//other assignments
fseek(file,0,SEEK_END);
fwrite(&newRecord,sizeof(book_list),1,file);
fclose(file);
While reading use below.
file = fopen(name,"r+");
book_list record;
fseek(file,0,SEEK_SET);
int i=0;
while(true){
fread(&record,sizeof(book_list),1,file);
if(feof(file))
break;
myBookList[i].bookNumber = record.bookNumber;
//other assignments
i++;
}
fclose(file);
Note: I'm not sure this is working properly with string class.I have used this with char[SIZE] and strcpy. My suggestion is try this first with built-in types like int, float, char etc.

C++: cin >> *char

So, I'm currently writing a line editor as a learning project on I/O, writing files, and the like. It is written in C++, and I am currently trying to write out to a file of the user's choosing. I have CLI arguments implemented, but I currently have no idea how to implement an in program way of specifying the file to write to.
char *filename;
if (argc >= 2){
filename = argv[1];
} else{
cout << "file>";
cin >> filename;
cin.ignore();
}
This works perfectly well when I use command line arguments; however, whenever I do not, as soon as I start the program, it Segmentation Faults. The place where I use the actual filename is in the save command:
void save(char filename[], int textlen, string file[]){
ofstream out(filename);
out << filestring(textlen, file);
out.close();
}
Which also works perfectly well. Is there any way you can help me? Full source code, for review, is up on https://github.com/GBGamer/SLED
The problem is that char* filename is just a pointer to some memory containing characters. It does not own any memory itself.
When you use the command line argument, the program handles storing that string somewhere, and you get a pointer to it. When you try to read using cin >> filename there isn't actually anywhere to store the read data.
Solution: Replace char* filename with std::string filename (and #include <string>).
Then to open the output file, you need a c-style string (null terminated char array). std::string has a function for this. You would write
std::ofstream out(filename.c_str());
^^^^^
Or, in fact, if you can use a recent compiler with c++11 features, you don't even need to use c_str(). A new std::ofstream constructor has been added to accept a std::string.
Your filename variable points to argv[1] when command line argument is provided, it does not need memory to be allocated but when going in else block, you have not allocated memory to filename. Its just a pointer.
Use malloc to assign filename some memory then take user input.
filename = (char *)malloc(sizeof(char)*(FILE_NAME_LENGTH+1))

Reading a fixed number of chars with << on an istream

I was trying out a few file reading strategies in C++ and I came across this.
ifstream ifsw1("c:\\trys\\str3.txt");
char ifsw1w[3];
do {
ifsw1 >> ifsw1w;
if (ifsw1.eof())
break;
cout << ifsw1w << flush << endl;
} while (1);
ifsw1.close();
The content of the file were
firstfirst firstsecond
secondfirst secondsecond
When I see the output it is printed as
firstfirst
firstsecond
secondfirst
I expected the output to be something like:
fir
stf
irs
tfi
.....
Moreover I see that "secondsecond" has not been printed. I guess that the last read has met the eof and the cout might not have been executed. But the first behavior is not understandable.
The extraction operator has no concept of the size of the ifsw1w variable, and (by default) is going to extract characters until it hits whitespace, null, or eof. These are likely being stored in the memory locations after your ifsw1w variable, which would cause bad bugs if you had additional variables defined.
To get the desired behavior, you should be able to use
ifsw1.width(3);
to limit the number of characters to extract.
It's virtually impossible to use std::istream& operator>>(std::istream&, char *) safely -- it's like gets in this regard -- there's no way for you to specify the buffer size. The stream just writes to your buffer, going off the end. (Your example above invokes undefined behavior). Either use the overloads accepting a std::string, or use std::getline(std::istream&, std::string).
Checking eof() is incorrect. You want fail() instead. You really don't care if the stream is at the end of the file, you care only if you have failed to extract information.
For something like this you're probably better off just reading the whole file into a string and using string operations from that point. You can do that using a stringstream:
#include <string> //For string
#include <sstream> //For stringstream
#include <iostream> //As before
std::ifstream myFile(...);
std::stringstream ss;
ss << myFile.rdbuf(); //Read the file into the stringstream.
std::string fileContents = ss.str(); //Now you have a string, no loops!
You're trashing the memory... its reading past the 3 chars you defined (its reading until a space or a new line is met...).
Read char by char to achieve the output you had mentioned.
Edit : Irritate is right, this works too (with some fixes and not getting the exact result, but that's the spirit):
char ifsw1w[4];
do{
ifsw1.width(4);
ifsw1 >> ifsw1w;
if(ifsw1.eof()) break;
cout << ifsw1w << flush << endl;
}while(1);
ifsw1.close();
The code has undefined behavior. When you do something like this:
char ifsw1w[3];
ifsw1 >> ifsw1w;
The operator>> receives a pointer to the buffer, but has no idea of the buffer's actual size. As such, it has no way to know that it should stop reading after two characters (and note that it should be 2, not 3 -- it needs space for a '\0' to terminate the string).
Bottom line: in your exploration of ways to read data, this code is probably best ignored. About all you can learn from code like this is a few things you should avoid. It's generally easier, however, to just follow a few rules of thumb than try to study all the problems that can arise.
Use std::string to read strings.
Only use fixed-size buffers for fixed-size data.
When you do use fixed buffers, pass their size to limit how much is read.
When you want to read all the data in a file, std::copy can avoid a lot of errors:
std::vector<std::string> strings;
std::copy(std::istream_iterator<std::string>(myFile),
std::istream_iterator<std::string>(),
std::back_inserter(strings));
To read the whitespace, you could used "noskipws", it will not skip whitespace.
ifsw1 >> noskipws >> ifsw1w;
But if you want to get only 3 characters, I suggest you to use the get method:
ifsw1.get(ifsw1w,3);