I'm currently working with std::fstream and have the following class:
(Note that the file is opened on constructor and should stay open during all read / write operation, only close when destructed).
MyFileClass
{
public:
MyFileClass( const std::string& file_name ) { m_file.open( file_name ) };
~MyFileClass() { m_file.close() };
bool read( std::string& content );
bool write( std::string& data );
private:
std::fstream m_file;
}
Now I have some sample code:
MyFileClass sample_file;
sample_file.write("123456");
sample_file.write("abc");
Result will be "abc456" because when the stream is open and we're writing with truncate mode it will always write on top of what's currently in there.
What I would like to have is to clean up everytime before we write so at the end I'll have only what's newest in there, in this case "abc".
And the current design is if the file is not there, it will be created only on write, but not on read (read will return error code if file is not present).
My write function is:
bool
MyFileClass::write( const std::string& data )
{
m_file.seekg( 0 );
if ( !m_file.fail( ) )
{
m_file << data << std::flush;
}
return m_file.fail( ) ? true : false;
}
Is there any way to clear the current content of the file before flushing the data?
to be able to write to the end of file use flag ios::app instead.
your code is full of mistakes:
1- you also trying to write a class string to file which is not correct. if you want to do so use serialization. in your case just convert it to constant character string.
2- your write and read functions defined to take a reference to string but you pass by value! (passing "12345" and "abc")
3- why you seek input pointer? (seekg)? as long as you are trying to write??!!
you may meant seekp() seeking output pointer; even in this case for what reason to do so? if you want to append text to the end use ios::app at the opening file.
if you want to clearing the content at any write operation then you should have two file streams one for reading and other for writing so the one for writing uses flag ios::out | ios::trunc. because ios::trunc does nothing in reading/writing mode.
4- if you really want to pass by reference then you must declare string objects in main passing to them values ("abc" and "12345" for each one) then pass these strings to write and read not the values.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class MyFileClass
{
public:
MyFileClass( std::string file_name );
~MyFileClass() { m_file.close(); }
bool read ( std::string content );
bool write( std::string data );
private:
std::fstream m_file;
};
MyFileClass::MyFileClass( std::string file_name )
{
m_file.open( file_name.c_str(), ios::out | ios::in | ios::app);
if(!m_file)
cout << "Failed to open file!" << endl;
}
bool MyFileClass::write( const std::string data )
{
if ( !m_file.fail( ) )
{
m_file << data.c_str() << std::flush;
}
return m_file.fail( ) ? true : false;
}
int main()
{
std::string sFile = "data.dat";
MyFileClass sample_file(sFile);
sample_file.write("123456");
sample_file.write("abc");
return 0;
}
Related
Some days ago I watched a computerphile video about grep and thought, 'why don't make my own version of it in c++?'.
So I began writing the code, but I encountered the problem at the very beginning of the program, when all the data in the stored file ( in my case txt ) have to be copied in the temporary file ( the one you work with ), of my string variable not writing into the temporary file, although the data of the stored file are succesfully put in the string.
I tried changing more then once how the string is written in the temporary file ( using classic << command, using write, using fputs and using fputc ), but none of these works.
Here's the code:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
#pragma warning(suppress : 4996) //disable compiler error for use of deprecated function ( std::tmpnam )
std::fstream temp_file ( std::tmpnam(NULL) ); //creates temporay file
void tmp_init(std::fstream& static_file) {
//copy all the contents of static_file into temporary file
std::string line; //support string for writing into temporary file
std::cout << "copying\n";
while (std::getline(static_file, line))
//writes into the support string until file is ended
temp_file << line; //writes into temporary file with string
std::cin.ignore(); //clears input buffer
}
void output() { //output of temporary file
std::cout << "Output:\n";
std::string output_line;
//support string for output write the output
while ( std::getline(temp_file, output_line))
//copies line to line from the temporary file in the support string
std::cout << output_line; //output of support string
std::cin.ignore();//clears input buffer
}
int main() {
std::fstream my_file; //creates static file
my_file.open("file.txt"); //open the file
if (my_file.is_open()) std::cout << "Open\n";
//Check if file is opened correctely
tmp_init(my_file);
//copy all contents of the static file in the temporary_file
output(); //output of temporary file
std::cin.get();
}
Any suggestion?
EDIT:
I found a parallel solution for this, not creating a temporary file using std::tmpnan (NULL) but creating a file with filename (~ + static file filename ) and then deleting it from the hard drive with std::remove ( temporary file filename ).
Before using std::remove() remember to call the method close() on the temporary file or is not going to remove it ( this is because the file is created when you call close on it, and by not doing it remove won't find the file and thus won't remove it).
The code:
class file : public std::fstream {
public:
std::string path;
file(std::string&& file_path) {
path = file_path;
std::fstream::open(path, std::ios::out);
}
};
int main() {
file static_file("file.txt");
file temp_file('~' + static_file.path);
static_file.close();
temp_file.close();
std::remove(temp_file.path.c_str() );
}
I am working on a project and have gotten completely stuck. Basically I have to read input from a file and print to an output file. I have already done all this, but now, the variables are supposed to be arrays, and I am stuck.
Here are the instructions:
Add a new function: collectData
(a) This function should take in the plans, comics, and input file stream as parameters
(b) It should contain a loop that calls getPlan and getComics until the arrays are filled up
(c) You should use some sort of counter variable to track which array element you're on.
here is my code: (I am confused on how to fill the arrays)
void collectData(char plan[], ifstream& fin, int SIZE) {
while (!fin.eof( )) {
getPlan(plan[],fin);
for(int i=1; i<SIZE ; i++) {
plan[i] = ;
}
}
}
Typically when I'm reading and writing data from files, especially when reading them;
I like to create a Data Structure that will represent the information that I'm pulling from the file. You will have to know how the file is structured in order to read the contents from it. Typically there are 3 different ways; you can read a single line at a time, you can read line by line until all lines have been read, or you can read everything from the file all in one go. There are ways to read different amount of bytes but that's a little more complicated and beyond the scope of this design process. What I normally do is; I'll read the contents from the file and store them into either a string, or a set of strings. Then after I retrieved the information from the file; I can then close it and be done with it. Once I have that information stored; then I will parse the string data, and from there I will then populate my Data Structures on the parsed data. I like breaking things down into individual functions to separate their logic and responsibility.
Your code structure may look something like this:
struct MyDataType {
// the contents that you will store from a file.
};
// A basic method to split a string based on a single delimiter
std::vector<std::string> splitString( const std::string& s, char delimiter ) {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream( s );
while( std::getline( tokenStream, token, delimiter ) ) {
tokens.push_back( token );
}
return tokens;
}
// Similar to above but with the ability to use a string as a delimiter as opposed to just a single char
std::vector<std::string> splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true ) {
std::vector<std::string> tokens;
if( strDelimiter.empty() ) {
tokens.push_back( strStringToSplit );
return tokens;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if( keepEmpty || !strTemp.empty() ) {
tokens.push_back( strTemp );
}
if( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return tokens;
}
// This function will open a file, read a single line
// closes the file handle and returns that line as a std::string
std::string getLineFromFile( const char* filename ) {
std::ifstream file( filename );
if( !file ) {
std::stringstream stream;
stream << "failed to open file " << filename << '\n';
throw std::runtime_error( stream.str() );
}
std::string line;
std::getline( file, line );
file.close();
return line;
}
// This function will open a file and read the file line by line
// storing each line as a string and closes the file then returns
// the contents as a std::vector<std::string>
void getAllLinesFromFile( const char* filename, std::vector<std::string>& output ) {
std::ifstream file( filename );
if( !file ) {
std::stringstream stream;
stream << "failed to open file " << filename << '\n';
throw std::runtime_error( stream.str() );
}
std::string line;
while( std::getline( file, line ) ) {
if( line.size() > 0 )
output.push_back( line );
}
file.close();
}
// This function will open a file and read all of the file's contents and store it into
// a large buffer or a single string.
void getDataFromFile( const char* filename, std::string& output ) {
std::ifstream file( filename );
if( !file ) {
std::stringstream stream;
stream << "failed to open file " << filename << '\n';
throw std::runtime_error( stream.str() );
}
std::stringstream buf;
buf << file.rdbuf();
output.clear();
output.reserve( buf.str().length() );
output = buf.str();
}
// The declaration of this can vary too; depending on if you are doing a single line
// from the file, doing single line at a time for the entire file, or reading all
// of the contents from a large buffer.
void parseDataFromFile( const std::string& fileContents, std::vector<std::string>& output, std::vector<MyDataStructure>& data ) {
// This will vary on the file's data structure,
// but this is where you will call either of the `splitString` functions
// to tokenize the data.
// You will also use the `std::string's` conversion utilities such as
// std::stoi(...)... to convert to your basic types
// then you will create an instance of your data type structure
// and push that into the vector passed in.
}
Then your main would look something like this: I'll use the line by line version
int main() {
try {
std::string fileContents;
getAllinesFromFile( "test.txt", fileContents );
std::vector<std::string> tokens;
std::vector<MyDataStructure> data;
parseDataFromFile( fileContents, tokens, data );
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This allows the code to be readable, more modular, reusable, and in some ways even generic. It also helps to keep minimize the amount of debugging, and lessens the code management.
-Note- Also if you looked carefully at my functions where I'm reading in the data from the file; you will not see while( !file.eof() )! This is bad code practice! The best way is to either use std::getline(...) or the stream << operators within a while loop to read in the data.
If I have a simple function that prints to standard output maybe something like an integer or lets say a string like "Flipy flops", then is there a way to call the same function but instead of printing to standard output it prints the string "Flipy flops" to a file stream? (provided of course I've opened the file and all that stuff).
Yes just give it an ostream& parameter
void my_function(...)
{
cout << ...
}
becomes
void my_function(ostream& out, ...)
{
out << ...
}
Using fstream works just like cin and cout.
void SomeMethod( )
{
ofstream myFile( "myFile.txt" );
myFile << FlipyFlops( );
myFile.close( );
}
char* FlipyFlops( )
{
return "flipy flops"; // or "flippy floppies", whichever you prefer
}
ofstream is for output to a file and ifstream is for reading from a file.
I want to write a std::wstring onto a file and need to read that content as std:wstring. This is happening as expected when the string as L"<Any English letter>". But the problem is happening when we have character like Bengali, Kannada, Japanese etc, any kind of non English letter. Tried various options like:
Converting the std::wstring to std::string and write onto the file and reading time read as std::string and convert as std::wstring
Writing is happening (I could see from edito) but reading time getting wrong character
Writing std::wstring onto wofstream, this is also not helping for
native language character letters like std::wstring data = L"হ্যালো ওয়ার্ল্ড";
Platform is mac and Linux, Language is C++
Code:
bool
write_file(
const char* path,
const std::wstring data
) {
bool status = false;
try {
std::wofstream file(path, std::ios::out|std::ios::trunc|std::ios::binary);
if (file.is_open()) {
//std::string data_str = convert_wstring_to_string(data);
file.write(data.c_str(), (std::streamsize)data.size());
file.close();
status = true;
}
} catch (...) {
std::cout<<"exception !"<<std::endl;
}
return status;
}
// Read Method
std::wstring
read_file(
const char* filename
) {
std::wifstream fhandle(filename, std::ios::in | std::ios::binary);
if (fhandle) {
std::wstring contents;
fhandle.seekg(0, std::ios::end);
contents.resize((int)fhandle.tellg());
fhandle.seekg(0, std::ios::beg);
fhandle.read(&contents[0], contents.size());
fhandle.close();
return(contents);
}
else {
return L"";
}
}
// Main
int main()
{
const char* file_path_1 = "./file_content_1.txt";
const char* file_path_2 = "./file_content_2.txt";
//std::wstring data = L"Text message to write onto the file\n"; // This is happening as expected
std::wstring data = L"হ্যালো ওয়ার্ল্ড";
// Not happening as expected.
// Lets write some data
write_file(file_path_1, data);
// Lets read the file
std::wstring out = read_file(file_path_1);
std::wcout<<L"File Content: "<<out<<std::endl;
// Let write that same data onto the different file
write_file(file_path_2, out);
return 0;
}
How a wchar_t is output depends on the locale. The default
locale ("C") generally doesn't accept anything but ASCII
(Unicode code points 0x20...0x7E, plus a few control
characters.)
Any time a program handles text, the very first statement in
main should be:
std::locale::global( std::locale( "" ) );
If the program uses any of the standard stream objects, the code
should also imbue them with the global locale, before any
input or output.
To read and write unicode files (assuming you want to write unicode characters) you can try fopen_s
FILE *file;
if((fopen_s(&file, file_path, "w,ccs=UNICODE" )) == NULL)
{
fputws(your_wstring().c_str(), file);
}
One possible problem may be when you read the string back, because you set the length of the string to the number of bytes in the file and not the number of characters. This means that you attempt to read past the end of the file, and also that the string will contain trash at the end.
If you're dealing with text files, why not simply use the normal output and input operators << and >> or other textual functions like std::getline?
Later edit: this is for Windows (since no tag was present at the time of the answer)
You need to set the stream to a locale that supports those characters . Try something like this (for UTF8/UTF16):
std::wofstream myFile("out.txt"); // writing to this file
myFile.imbue(std::locale(myFile.getloc(), new std::codecvt_utf8_utf16<wchar_t>));
And when you read from that file you have to do the same thing:
std::wifstream myFile2("out.txt"); // reading from this file
myFile2.imbue(std::locale(myFile2.getloc(), new std::codecvt_utf8_utf16<wchar_t>));
Do not use wstring or wchar_t. On non-Windows platforms wchar_t is pretty much worthless these days.
Instead you should use UTF-8.
bool
write_file(
const char* path,
const std::string data
) {
try {
std::ofstream file(path, std::ios::out | std::ios::trunc | std::ios::binary);
file.exceptions(true);
file << data;
return true;
} catch (...) {
std::cout << "exception!\n";
return false;
}
}
// Read Method
std::string
read_file(
const char* filename
) {
std::ifstream fhandle(filename, std::ios::in | std::ios::binary);
if (fhandle) {
std::string contents;
fhandle.seekg(0, std::ios::end);
contents.resize(fhandle.tellg());
fhandle.seekg(0, std::ios::beg);
fhandle.read(&contents[0], contents.size());
return contents;
} else {
return "";
}
}
int main()
{
const char* file_path_1 = "./file_content_1.txt";
const char* file_path_2 = "./file_content_2.txt";
std::string data = "হ্যালো ওয়ার্ল্ড"; // linux and os x compilers use UTF-8 as the default execution encoding.
write_file(file_path_1, data);
std::string out = read_file(file_path_1);
std::wcout << "File Content: " << out << '\n';
write_file(file_path_2, out);
}
This is a beginner question. I am trying to find a string in text file and replace it back to the same file. Following code works fine collecting contents of file into buffer and replace the string . But when i try to keep the data back to same file, it is filled with some junk character. Please let me know what I am doing wrong ?
#include <iostream>
#include <fstream>
using namespace std;
const char *fileName = "Test.dat";
int main () {
// This is where we'll put the stuff we read from file
char buffer[ 100 ];
ifstream finout(fileName, ios_base::in | ios_base::out | ios_base::binary);
if(!finout.is_open())
{
cout << "Can not open file " << endl;
return(1);
}
while (finout.getline(buffer, sizeof(buffer))
{
string g( buffer );
string search = "am";
string replace = "was";
long j;
if ( (j = g.find(str2)) != string::npos)
{
g.replace(g.find(str2), str2.length(), "str");
finout.write((char *) &g, sizeof(g)); //This won't work
}
cout << g << "\n";
finout.close();
return 0;
}
My Test.dat file contain following information:
Hello, How are you?
I am fine.
When you are read/write as a text file, do not open it by ios_base::binary
You put finout.close(); inside your reading loop, so it just work for one line.
When you are reading/writing a file as a text, use text stream methods and operators.
You are trying to read the size of your string with the sizeof() operator.
This wont work, because it is a keyword, that gives you the non-dynamic size of the object or type.
You should use g.size() to access the string size!
But on the first place, you can handle the stream handle your bug:
finout << g;
will do the job.
First, you want to both read and write a file, so use fstream not ifstream.
Second, you have a text file, so don't use ios_base::binary
Third (char*) &g where g is std::string doesn't work, use g.c_str() instead. (simply write
finout << g;
Now you can start thinking of the implmentation...