I have the following code:
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include "Person.h"
using namespace std;
int main()
{
// ========================================================================================
// part a - initialiaze 100 records, lastName = "unassigned", firstName = "", age = 0
ofstream outPerson_0("nameage.dat", ios::out | ios::binary);
// exit program if ofstream could not open file
if (!outPerson_0)
{
cerr << "File could not be opened." << endl;
exit(EXIT_FAILURE);
} // end if
Person blankPerson("unassigned", "", 0); // constructor zeros out each data member
// output 100 blank records to file
for (int i = 0; i < 100; ++i)
outPerson_0.write(reinterpret_cast< const char * >(&blankPerson), sizeof(Person));
// ========================================================================================
// part b - input 10 first names and ages and write them to file
string firstName;
string lastName;
int age;
fstream outPerson_1("nameage.dat", ios::in | ios::out | ios::binary);
// exit program if fstream cannot open file
if (!outPerson_1)
{
cerr << "File could not be opened." << endl;
exit(EXIT_FAILURE);
} // end if
// iterate 10 times to get first names and ages
for (int i = 0; i < 10; ++i)
{
// get user input
cout << "Enter last name, first name and age (space separated): ";
// set dummy values in object
std::string s = std::to_string(i);
blankPerson.setLastName(s);
blankPerson.setFirstName(s);
blankPerson.setAge(i);
// seek position in file of user-specified record, using i
auto pos = (i) * sizeof(Person);
outPerson_1.seekp(pos);
// write user-specified information in file
outPerson_1.write(reinterpret_cast<const char *>(&blankPerson), sizeof(Person));
}
// ========================================================================================
// part c - update record with no info
}
Part a populated 100 objects with dummy values, and writes to file. Part b updates the first 10 objects with dummy values generated by iterator i. For some strange reason, part b does not work properly. Could someone tell me why? The result is exactly the same as when I run part a alone.
Normally object is not suggested to write to file directly, but just by case, your code has other problem:
the ofstream and fstream instances have its own internal buffer, the data will be written into internal buffer before flushing/syncing to underlying file.
Before quitting the program,
fstream outPerson_1 will destroyed
its internal buffer will be flushed to file "nameage.dat"
ofstream outPerson_0 is destroyed
its internal buffer will be flushed to file "nameage.dat" again
(as for why, it is another topic, don't talk here)
Since the data in outPerson_0 is more than the data in outPerson_1, so the outPerson_1 data is overwritten, and then you can't see it, if you write more data into outPerson_1, you will observe it.
There may be 2 options for your code:
Option#1:
flush the data after writing the first 100 person data
// output 100 blank records to file
for (int i = 0; i < 100; ++i)
outPerson_0.write(reinterpret_cast< const char * >(&blankPerson), sizeof(Person));
outPerson_0.flush();
Option#2:
Add ios::app flag to let ofstream/fstream to append the data to the file
ofstream outPerson_0("nameage.dat", ios::out | ios::binary | ios::app);
fstream outPerson_1("nameage.dat", ios::in | ios::out | ios::binary | ios::app);
Related
For the sake of simplicity I wrote a simple code to reproduce my problem. As you can see on the code i created a struct with two members then I created and array of the struct type then initialized it student newStudent[3] ={{"joseph",20}, {"yonas",30},{"miryam",40}};. I stored all the info from the struct to a binary file newFile.write(reinterpret_cast<char*>(newStudent), 3 * sizeof(student));(everything is fine until here) then i created another array student loadedStudent[3]; to load into, all the data from the binary file and output the loaded data using a for loop cout<<"Name: "<<loadedStudent[i].name<<"Age: "<<loadedStudent[i].age<<endl;. The problem is that the data i stored is joseph",20, "yonas",30,"miryam",40 but the program is outputting garbage values Name: 8H???Age: 1 Name: J???Age: 1 Name: ?I???Age: 32766.
Why is that?
#include <iostream>
#include <fstream>
using namespace std;
struct student{
char name[10];
int age;
};
int main()
{
student newStudent[3] ={{"joseph",20}, {"yonas",30},{"miryam",40}};
fstream newFile;
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::binary);
//for(int i = 0; i<3; i++){
//cout<<"Name: "<<newStudent[i].name<<" Age: "<<newStudent[i].age<<endl;
//}
if(newFile.is_open()){
newFile.write(reinterpret_cast<char*>(newStudent), 3 * sizeof(student));
}else cout<<"faild to open file";
student loadedStudent[3];
newFile.seekg(0, ios::beg);
if(newFile.is_open()){
newFile.read(reinterpret_cast<char*>(loadedStudent), 3 * sizeof(student));
newFile.close();
}else cout<<"faild to open file";
for(int i = 0; i<3; i++){
cout<<"Name: "<<loadedStudent[i].name<<"Age: "<<loadedStudent[i].age<<endl;
}
When you opened the file you only opened it as output ios::out you shoul've also included ios::in so you can access the file. Now you're printing the indeterminate values of an uninitialized array.
change this
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::binary);
into
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::in | ios::binary);
newFile.open("/Users/josephfeleke/Desktop/abeltest/file.bin", ios::out | ios::binary);
This is opening the file for output only. You need ios::in | ios::out to be able to both read and write.
Hi guys I am working on an rpg project and I am creating player files so they can save their progress and such.
I've made a test program so I can show you on a more simple scale of what I am looking for
Code:
#include <iostream>
#include <fstream>
#include <string>
int main(){
std::string PlayerFileName;
std::cout << "Name Your Player File Name: ";
std::cin >> PlayerFileName;
std::ofstream outputFile;
std::string FileName = "Players/" + PlayerFileName;
outputFile.open(FileName); // This creates the file
// ...
}
I want to check and see if the Player File Name already exists the the Players directory so people cant save over their progress.
Thanks!
I suggest opening the file in binary mode and using seekg() and tellg() to count it's size. If the size is bigger than 0 bytes this means that the file has been opened before and has data written in it:
void checkFile()
{
long checkBytes;
myFile.open(fileName, ios::in | ios::out | ios::binary);
if (!myFile)
{
cout << "\n Error opening file.";
exit(1);
}
myFile.seekg(0, ios::end); // put pointer at end of file
checkBytes = myFile.tellg(); // get file size in bytes, store it in variable "checkBytes";
if (checkBytes > 0) // if file size is bigger than 0 bytes
{
cout << "\n File already exists and has data written in it;
myFile.close();
}
else
{
myFile.seekg(0. ios::beg); // put pointer back at beginning
// write your code here
}
}
Check if file exists like this:
inline bool exists (const std::string& filename) {
struct stat buffer;
return (stat (filename.c_str(), &buffer) == 0);
}
Using this needs to remember to #include <sys/stat.h>.
-
In C++14 it is possible to use this:
#include <experimental/filesystem>
bool exist = std::experimental::filesystem::exists(filename);
& in C++17: (reference)
#include <filesystem>
bool exist = std::filesystem::exists(filename);
I'm trying to read a binary file and I need to determine its size, but regardless of the method I've tried, I'm getting a size of zero.
For example:
fstream cbf(address, ios::binary | ios::in | ios::ate);
fstream::pos_type size = cbf.tellg(); // Returns 0.
char* chunk = new char[size];
cbf.read(chunk, size);
//...
If I were to use the following:
#include <sys/stat.h>
struct stat st;
stat(address.c_str(),&st);
int size = st.st_size;
The size is still zero. I've also tried the following, but it's still zero.
File* fp;
fp = open(address.c_str(), "rb");
How do I get the size of the file?
Thanks for the responses... I've identified the problem:
The binary file I was trying to access was created during the execution, and I just had forgotten to close it before trying to read from it...
Neither of your examples checks for failure. This program, using your first method, works perfectly well for me. It correctly identifies the size of /etc/passwd and the non-existence of /etc/motd.
#include <fstream>
#include <iostream>
#include <string>
void printSize(const std::string& address) {
std::fstream motd(address.c_str(), std::ios::binary|std::ios::in|std::ios::ate);
if(motd) {
std::fstream::pos_type size = motd.tellg();
std::cout << address << " " << size << "\n";
} else {
perror(address.c_str());
}
}
int main () {
printSize("/etc/motd");
printSize("/etc/passwd");
}
Try to load the file in this method.
Note: Use ifstream insted of fstream in this line ifstream cbf(address, ios::binary | ios::in );
long size;
ifstream cbf(address, ios::binary | ios::in);
cbf.seekg(0, ios::end);
size=cbf.tellg();
cbf.seekg(0, ios::beg);
char* chunk = new char[size];
cbf.read(chunk, size);
I work on using extensible hash to find the query FASTER.
my code is this steps:
1)read the main text file ( hudge file 4 GiB)
the file is some thing like this :
12435 alex romero
13452 jack robert
13485 marya car
45132 gun tribble
...
the user want to know that for example the key 12435 is related to what ?(answer:alex romero)
2)create a hash table for the keys in the file (i means 12435,13452,13485,...)
and i save this tables dynamically in hard disk in some text files named:0.txt,1.txt,2.txt and ....
3)when the user get query to the program then the program must calculate the hash function on its value and find the file that must be read then it is faster to find the result.
i have a function:
#define LIMIT 7
void writeInFile(int key , const char* charPos ){
int remainder = key%(LIMIT*LIMIT);
string myFileName;
ostringstream convert;
convert << remainder ;
myFileName = convert.str();
myFileName += ".txt";
FILE *my_file;
my_file = fopen(myFileName.c_str() ,"a");
fputs("\n" ,my_file);
fputs(charPos , my_file);
//fclose(my_file);
}
i wondered that when i use fclose then the speed of the program will reduced !!!
then i dont use it at the end of the function but a problem that is when i use this function many times i can't close them then i cant get access to the files.
i want to create a "list" of FILEs that i can send refrence of them to the function like: FILE &* myFiles[] or FILE &** myFiles as 3th parameter that function gets...
but i see the errors .i dont know how is its syntax of this.i means some syntax like:
void writeInFile(int key , const char* charPos , FILE &*myFiles[] ) // this makes error
the other method that i think is that can i close those files that now I can't access to them ? or can i change my code that cause this ?
update:this is my full code
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
#include <sstream>
#include <stdio.h>
#include <vector>
#define LIMIT 7
using namespace std;
void writeInFile(int key , const char* charPos ){
int remainder = key%(LIMIT*LIMIT);
string myFileName;
ostringstream convert;
convert << remainder ;
myFileName = convert.str();
myFileName += ".txt";
FILE *my_file;
my_file = fopen(myFileName.c_str() ,"a");
fputs("\n" ,my_file);
fputs(charPos ,my_file);
//fclose(my_file);
}
int main(){
string fileName;
cout << "hello, please inter your file destination : " ;
cin >> fileName;
ifstream myFile ;
myFile.open(fileName.c_str() ,ifstream::in |ifstream::binary);
cout << "building the hash,please wait";
string havij;//:D this is an unusable variable in this section :))
int current;
int index;
int isCout=0;
char buffer [10];
//FILE *my_file[49];
while(!myFile.eof()){
cout << isCout << endl;
isCout++;
index = myFile.tellg();
itoa(index , buffer ,10);
//cout << buffer << endl;
myFile >> current;
writeInFile(current ,buffer);
getline(myFile,havij);
}
myFile.close();
fstream test;
//for(int i =0 ; i<LIMIT*LIMIT-1 ; i++){
// fclose(my_file[i]);
//}
cout << endl << "static extensible hash structure builded please inter your query : " ;
int query;
cin >> query;
int remainder = query%(LIMIT*LIMIT);
string myFileName;
ostringstream convert;
convert << remainder ;
myFileName = convert.str();
myFileName += ".txt";
ifstream myFile2;
//myFile2 is now the files that create by program like : 12.txt ,25.txt ,....
myFile2.open(myFileName.c_str() , ifstream::in | ifstream::binary);
ifstream mainFile;
mainFile.open(fileName.c_str(), ifstream::in | ifstream::binary);
int position;
string wanted;
int tester;
while(!myFile2.eof()){
myFile2 >> position;
mainFile.seekg(position ,ios::beg);
mainFile >> tester;
if (tester == query ){
getline(mainFile ,wanted);
cout << "the result of the key " << tester << " is " << wanted << endl;
}
}
return 0;
}
Or you could do this:
void writeInFile(int key , const char* charPos , std::vector<std::ofstream> & myFiles );
I find this makes my brain hurt less.
If you don't close your file in the same context where the FILE* variable is declared, you are leaking that file descriptor. At some point you are going to run out of resources and the program will crash.
Since you are using C++ from the snippet you've shown, then you would be much better off using std::vector and std::ofstream.
void writeInFile(int key, const char* charPos, std::vector<std::ofstream> my_files )
As has been said, you should close the file in the scope it is opened. This is the default behavior for C++ streams.
However it does not mean that you should open/close for each word you add! The files you write to should be kept open as long as you have things to add to them (beware there is a limit in the number of file descriptors an OS can handle).
Therefore, you should have:
Open all destination files (*)
For each line, select the appropriate file in a table/map and write into it
Close all destination files
(*) As said, you might run into a hard limit, in this case there is not much you can do, caching is unlikely to be effective if your hash function is worth anything. A possibility would be to make several runs over the big file and saving only a portion of the hashes at each run (say run 1: hashes in [0-9], run 2: hashes in [10-19], ...).
The fundamental type FILE* or ofstream that you use is of little importance, both have comparable speed (correctly tuned).
I'm trying to open a binary file for writing without erasing the content. But I do not want to write to eof. I want to write to a specific position in file.
Here is a litte example:
ofstream out("test.txt", ios::binary | ios::app);
for(int i = 0; i < 100; i++)
out.put('_');
out.write("Hallo", 5);
out.close();
ofstream out2("test.txt", ios::binary | ios::app);
out2.seekp(10);
out2.write("Welt", 4);
out2.close();
If using app, seek doesn't work. If not using app opening file erases data. Does anybody know an answer?
try the second overload of seekp, which allows you to provide an offset and a direction, this could be begining of file in your case (i.e. ios_base::beg). This of course assumes you know what you are doing and all you want to do is overwrite an existing number of characters.
EDIT: here is fully working example:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
{
ofstream out("test.txt", ios::binary);
for(int i = 0; i < 100; i++)
out.put('_');
out.write("Hallo", 5);
}
{
fstream out2("test.txt", ios::binary | ios::out | ios::in);
out2.seekp(10, ios::beg);
out2.write("Welt", 4);
}
}
When opening with ios::app, it is as if you open a new file that just happened to be attached to an existing file: you can not access the existing file. I'm not sure, because I would do as in Kerrek's answer, but if you really want to try, you probably have to open with "ios::in | ios::out", similar to fopen("test.txt", "rw").
Or as crashmstr points out: ios::out might be enough.
You cannot magically extend the file from the middle. Perhaps easiest to write to a new file: First copy the initial segment, then write your new data, then copy the remaining segment. When all is done, you can overwrite the original file.
According to the specification of fstream here
fstream::open
the ios::app "Sets the stream's position indicator to the end of the stream before EACH output operation." So ios::app doesn't work for replacing, seeks of any sort fail, at least for me.
Just using ios::out does wipe out the file contents preserving only the size, basically turning the file into trash.
ios::in|ios::out turned out as the only working thing for me.
Working Code: This code searches for a string (OLD-STRING) in cout.exe and replaces with a new string (NEW-STRING).
`#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
fstream ifs;
ifs.open ("C:\\Users\\user\\Desktop\\cout.exe", fstream::binary | fstream::in | fstream::out);
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
size_t pos = str.find("OLD-STRING");
if (pos != string::npos)
{
cout << "string found at position: " << int(pos) << endl;
ifs.seekp(pos);
ifs.write("NEW-STRING", 10);
}
else
{
cout << "could not find string" << endl;
}
if (ifs.is_open())
ifs.close();
return 0;
}`