c++ seekp(0,ios::end) not working - c++

Apologize for my poor English.
I am stuck by fstream in C++. Here is my code.
#include<iostream>
#include<fstream>
using namespace std;
struct TestStruct
{
int a;
char str[30];
TestStruct(int a_, const char* s)
{
a = a_;
strcpy_s(str,sizeof(char)*30, s);
}
TestStruct() = default;
};
int main()
{
fstream output("out.bin", ios::out|ios::binary);
output.seekp(0,ios::end);
cout << output.tellp() << endl;
for (int i = 0; i < 15; i++) {
TestStruct a(10*i, "asdadas");
output.write(reinterpret_cast<char*>(&a), sizeof(a));
}
output.close();
fstream input("out.bin", ios::in | ios::binary);
input.seekg(2 * sizeof(TestStruct), ios::beg);
for (int i = 0; i < 5; i++) {
TestStruct a;
input.read(reinterpret_cast<char*>(&a), sizeof(a));
cout <<"file_pointer"<<input.tellg()<<'\t'<<a.a << endl;
}
}
I use seekp(0,ios::end) to add new entry in the file. So the file should get lager when I run this code. But actually the file haven't change at all.
Here is the output:
> 0 <--tellp() always return 0
> file_pointer108 20
> file_pointer144 30
> file_pointer180 40
> file_pointer216 50
> file_pointer252 60

Add ios::app to the output's flags. You won't need to do output.seekp(0, ios::end); then.

While it may not seem like it seekp(0, ios::end) is actually working.
The reason it returns 0 is because you accidentally create a new empty file.
And the end cursor position of a new empty file is 0.
It creates a new file because of the file mode you use:
output("out.bin", ios::out|ios::binary);
https://en.cppreference.com/w/cpp/io/basic_filebuf/open

Related

Why am i getting blank output after writing this filehandling code in c++?

I have made a tester class where I take questions from a question pool text file and put random questions from there to a docx file. I want to know why my code is giving me blank output in the docx file.
my random function is working fine. I am selecting two two questions from three questions file.
Here is my code - `
void test()
{
string line;
fstream question1("questiondesc.txt",ios::in | ios::out | ios::app);
fstream testgen("GeneratedTest.docx",ios::trunc | ios::in | ios::out);
testgen.open("GeneratedTest.docx");
if(!question1.is_open())
{
question1.open("questiondesc.txt");
}
int i,num;
for (i = 0; i < 2; i++) {
num = random(1,12);
for(int i =1;i<=num;i++)
{
getline(question1,line);
}
question1.clear();
question1.seekg(0, ios::beg);
testgen<<line<<endl;
}
question1.close();
ifstream question2("questionmcq.txt");
if(!question2.is_open())
{
question2.open("questionmcq.txt");
}
for (i = 0; i < 2; i++) {
num = random(1,26);
while(num%2==0)
{
num = random(1,26);
}
for(int i =1;i<=num;i++)
{
getline(question2,line);
}
testgen<<line<<endl;
getline(question2,line);
testgen<<line<<endl;
question2.clear();
question2.seekg(0, ios::beg);
}
question2.close();
ifstream question3("questionanalytical.txt");
if(!question3.is_open())
{
question3.open("questionanalytical.txt");
}
for (i = 0; i < 2; i++) {
num = random(1,12);
for(int i =1;i<=num;i++)
{
getline(question3,line);
}
question3.clear();
question3.seekg(0, ios::beg);
testgen<<line<<endl;
}
question3.close();
testgen.close();
}
There are errors in your code. I will show them as a comment in the below listing. Additionally I will show (onw of many, and maybe not the best ) solutions for your problem.
You should break down your problem into smaller pieces and design more functions. Then, life will be easier.
Additionally. You´should write comments. If you write comments, then you will detect the problems by yourself.
Your code with my remarks:
#include <iostream>
#include <fstream>
#include <string>
#include <random>
using namespace std; // NO NEVER USE
int random(int from, int to) {
std::random_device random_device;
std::mt19937 generator(random_device());
std::uniform_int_distribution<int> distribution(from, to);
return distribution(generator);
}
void test()
{
string line; // Line is not initialized an not needed here. Pollutes namespace
fstream question1("questiondesc.txt", ios::in | ios::out | ios::app); // Opening a file with these flags will fail. Use ifstream
fstream testgen("GeneratedTest.docx", ios::trunc | ios::in | ios::out);// Opening a file with these flags will fail. Use ofstream
testgen.open("GeneratedTest.docx"); // File was alread opened and failed. Reopening will not work. It failed alread
if (!question1.is_open()) // Use if "(!question1)" instead. There could be also other error bits
{ // Always check the status of any IO operation
question1.open("questiondesc.txt"); // Will never work. Failer already
}
int i, num; // Variable not initialized and not needed here. Name space pollution
for (i = 0; i < 2; i++) {
num = random(1, 12); // This function was not defined. I redefined it
for (int i = 1; i <= num; i++) // i=1 and i<= reaaly) not i=0 and i<num?
{
getline(question1, line); // Always check status of any IO function
}
question1.clear();
question1.seekg(0, ios::beg);
testgen << line << endl;
}
question1.close(); // The destructor of the fstream will close the file for you
ifstream question2("questionmcq.txt"); // Now you open the file as ifstream
if (!question2.is_open()) // Do check for all possible flags.: If (!question2)
{
question2.open("questionmcq.txt"); // Will not work, if it failed in the first time
}
for (i = 0; i < 2; i++) { // So 2 times
num = random(1, 26);
while (num % 2 == 0) // If numbers are equal
{
num = random(1, 26); // Get an odd number
}
for (int i = 1; i <= num; i++) // Usually from 0 to <num
{
getline(question2, line);
}
testgen << line << endl;
getline(question2, line);
testgen << line << endl;
question2.clear();
question2.seekg(0, ios::beg);
}
question2.close(); // No need to close. Destructor will do it for you
ifstream question3("questionanalytical.txt"); // Now you open the file as ifstream
if (!question3.is_open()) // Wrong check. Check for all flags
{
question3.open("questionanalytical.txt"); // Will not help in case of failure
}
// Now this is the 3rd time with the same code. So, put it into a function
for (i = 0; i < 2; i++) {
num = random(1, 12);
for (int i = 1; i <= num; i++)
{
getline(question3, line);
}
question3.clear();
question3.seekg(0, ios::beg);
testgen << line << endl;
}
question3.close();
testgen.close();
}
int main() {
test();
return 0;
}
And here one possible solution. With functions to handler similar parts of the code:
#include <iostream>
#include <string>
#include <fstream>
#include <random>
#include <vector>
#include <tuple>
// From the internet: https://en.cppreference.com/w/cpp/numeric/random/random_device
int random(int from, int to) {
std::random_device random_device;
std::mt19937 generator(random_device());
std::uniform_int_distribution<int> distribution(from, to);
return distribution(generator);
}
std::string readNthLineFromFile(std::ifstream& ifs, int n) {
// Reset file to the beginning
ifs.clear();
ifs.seekg(0, std::ios::beg);
// Default return string in case of error
std::string result{ "\n*** Error while reading a line from the source file\n" };
// If getline fails or ifs is in fail state, the string will be default
for (; std::getline(ifs, result) && (n != 0); n--);
// Give back the desired line
return result;
}
void generateQuestion(std::ifstream& sourceFileStream, std::ofstream& destinationFileStream, int n, const bool twoLines = false) {
// We want to prevent readin the same question again
int oldLineNumber = 0;
// For whatever reason, do this 2 times.
for (size_t i = 0U; i < 2; ++i) {
// If we want to read 2 consecutive lines, then we should not come up with the last kine in the file
if (twoLines & (n > 1)) --n;
// Get a random line number. But no duplicates in the 2 loops
int lineNumber{};
do {
lineNumber = random(1, n);
} while (lineNumber == oldLineNumber);
// For the next loop execution
oldLineNumber = lineNumber;
// Read the random line
std::string line{ readNthLineFromFile(sourceFileStream, lineNumber) };
// And write it to the destination file
destinationFileStream << line << "\n";
// If we want to read to lines in a row
if (twoLines) {
// Read next line
line = readNthLineFromFile(sourceFileStream, ++lineNumber);
// And write it to the destination file
destinationFileStream << line << "\n";
}
}
}
int main() {
const std::string destinationFilename{ "generatedTest.txt" };
const std::string questions1Filename{ "questiondesc.txt" };
const std::string questions2Filename{ "questionmcq.txt" };
const std::string questions3Filename{ "questionanalytical.txt" };
// Here we store the filenames and if one or 2 lines shall be read
std::vector<std::tuple<const std::string, const size_t, const bool>> source{
{ questions1Filename, 12U, false },
{ questions2Filename, 26U, true },
{ questions3Filename, 12U, false }
};
// Open the destination file and check, if it could be opened
if (std::ofstream destinationFileStream(destinationFilename); destinationFileStream) {
// Now open the first source file and generate the questions
for (const std::tuple<const std::string, const size_t, const bool>& t : source) {
// Open source file and check, if it could be opened
if (std::ifstream sourceFileStream(std::get<0>(t)); sourceFileStream) {
generateQuestion(sourceFileStream, destinationFileStream, std::get<1>(t), std::get<2>(t));
}
else {
std::cerr << "\n*** Error. Could not open source file '" << std::get<0>(t) << "'\n";
}
}
}
else {
std::cerr << "\n*** Error: Could not open destination file '" << destinationFilename << "'\n";
}
return 0;
}

c++ i get duplicated info when i read a binary file

Im writing a vector of size three and when i read i get a vector of size 4 with the last index being a duplicate of the index 2.
Heres my code.
void IOManager::WriteBin(const string &filename, vector<userRank> highScorers, int rank) {
ofstream fsalida(filename, ios::out | ios::binary);
if (fsalida.is_open())
{
for (int i = 0; i < highScorers.size();i++) {
fsalida.write(reinterpret_cast<char*>(&highScorers[i]), sizeof(highScorers[i]));
}
//highScorers.size() is 3
fsalida.close();
}else cout << "Unable to open file for writing\n";
}
vector<userRank> IOManager::ReadBin(const string &filename) {
ifstream fentrada(filename, ios::in | ios::binary);
if (fentrada.is_open())
{
vector<userRank>bestPlayers;
for (int i = 0; fentrada.good(); i++) {
userRank tempUser;
fentrada.read(reinterpret_cast<char*>(&tempUser), sizeof(tempUser));
bestPlayers.push_back(tempUser);
}
//bestPlayers.size() is 4!!!!!! Im losing my mind
fentrada.close();
return bestPlayers;
}
else cout << "Unable to open file for reading\n";
}
Here's my UserRank struct
struct userRank
{
char userName [5];
int score;
};
A wild userRank apperars for some reason, does anybody know why?
I suggest reorganizing the read function:
userRank tempUser;
for (int i = 0;
fentrada.read(reinterpret_cast<char*>(&tempUser), sizeof(tempUser));
i++)
{
bestPlayers.push_back(tempUser);
}
Search the internet for "stackoverflow c++ why eof in while is bad".

Why do I see the contents of binary files?

Why I can open and view binary files . odd appearance that is impossible ?
http://codepad.org/OwX99H0p
Enter a string str -> char arr1[] -> FILEOUT.DAT
FILEOUT.DAT -> char arr2[] -> Printed screens
The code in question:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void NhapMang(char *&arr, string str , int &n)
{
n = str.length();
arr = new char[n];
for (int i = 0; i < n;i++)
{
arr[i] = str[i];
}
}
void XuatMang(char *arr, int n)
{
for (int i = 0; i < n;i++)
{
cout << arr[i];
}
}
void GhiFile(ofstream &FileOut, char *arr, int n)
{
FileOut.open("OUTPUT.DAT", ios::out | ios::binary);
FileOut.write(arr, n*sizeof(char));
FileOut.close();
}
void DocFile(ifstream &FileInt, char *&arr, int n)
{
FileInt.open("OUTPUT.DAT", ios::in | ios::binary);
arr = new char[n];
FileInt.read(arr, n*sizeof(char));
FileInt.close();
}
int main()
{
char *arr1;
int n1;
fflush(stdin);
string str;
getline(cin, str);
NhapMang(arr1, str,n1);
ofstream FileOut;
GhiFile(FileOut, arr1, n1);
char *arr2;
int n2 = n1;
ifstream FileInt;
DocFile(FileInt, arr2, n2);
XuatMang(arr2, n2);
delete[] arr1;
delete[] arr2;
system("pause");
return 0;
}
You're ultimately storing data in a file. What this data represents is up to you, keep in mind, it's all '1's and '0's in the end. When you open the file you've created with a text editor, it will try to interpret this data as text which doesn't give a readable result.
Imagine storing a liquid in a bottle. If you don't label it, no one knows what it is. If you then pour this liquid in your car, it will try to use this as gasoline and potentially wreck your engine. Computers, fortunately, are much more forgiving.
Most files store information about how the data can be interpreted in their headers so programs can check if the file type is supported or not. So trying to open this file in a media player for example is most likely telling you that this format is not supported instead of trying to interpret the data as a media.

segmentation fault when calling close on ifstream object

I am trying to read a text file into a two dimensional character array. When I call close on the ifstream object after extracting the data, I get a segmentation fault.
This works:
problem::problem(obj *o1, obj* o2, char *state_file)
{
ifstream infile;
string line;
infile.open(state_file, ios::in);
getline(infile,line);
infile.close();
}
This doesnt:
problem::problem(obj *o1, obj* o2, char *state_file)
{
ifstream infile;
string line;
//data is char data[6][7] and is declared in the header
//line is EXACTLY 7 characters lone
infile.open(state_file, ios::in);
for(int i = 5;i >= 0;i--)
{
getline(infile,line);
for(int j = 0;j < 7;j++)
data[i][j] = line[j];
}
cerr << "PROGRAM OK" << endl;
infile.close();
cerr << "The program doesn't get here" << endl;
//Some more constructor code
}
Why am I getting a segmentation fault when I call infile.close()?
SSCCE version that works with the same input file:
#include <string>
#include <fstream>
using namespace std;
class func
{
public:
func(char *);
private:
char data[6][7];
};
func::func(char *state_file)
{
ifstream infile;
string line;
infile.open(state_file, ios::in);
for(int i = 5;i >= 0;i--)
{
getline(infile,line);
for(int j = 0;j < 7;j++)
data[i][j] = line[j];
}
infile.close();
}
int main(int argc, char *argv[])
{
func *obj = new func(argv[1]);
delete obj;
return 0;
}
From main:
obj *p1 = new obj(&something);
obj *p2 = new obj(&something);
problem *p;
if(argc == 3)
p = new problem(p1, p2, argv[2]); //SEGFAULTS HERE
else
p = new problem(p1, p2);
from the header with the class declaration:
public:
problem(obj *, obj *);
problem(obj *, obj *, char *);
private:
char data[6][7];
Are you sure that your file always contains at least six lines?
The usual way to "iterate" on a ifstream is:
ifstream is("test.txt");
string line;
while(getline(is, line))
{
cout<<line<<endl;
}
I figured it out. The problem had something to do with how the object file was being linked during the build process. Removing all the .o files and rebuilding from scratch solved the problem. Thank you everyone for your input. I apologize for not doing a clean build from the beginning and wasting your time.

Issues with flushing cout after getting file data

I am trying to write an implementation of rc4. I am reading in plaintext from a file using an ifstream. I noticed that it wasn't outputting at the end of the file, so I tried the various ways of explicitly clearing the buffers. No matter which way (using an endl, appending \n, calling cout.flush()) I try to flush the buffer, I get a segfault. As a sanity check, I replaced my code with an example from the web, which I also tested separately. It works if I put it in its own file and compile it (e.g., it prints out the contents of the file, doesn't segfault, and doesn't require any calls to flush() or endl to do so), but not in my code.
Here is the offending bit of code (which works fine outside of my code; its copied pretty much directly from cplusplus.com)
ifstream is;
is.open("plain");
char c;
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
// cout.flush();
}
is.close(); // close file*/
Here is the full code: (warning, lots of commented out code)
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>
using namespace std;
static char s[256], k[256];
//static char *i, *j;
void swap(int m, int n, char t[256]){
char tmp = t[m];
t[m] = t[n];
t[n] = tmp;
}
char getByte(){
static char i(0), j(0);
i = (i+1)%256;
j = (j + s[i])%256;
swap(i, j, s);
return s[(s[i]+s[j]) % 256];
}
int main(int argc, char ** argv){
/*string key = argv[1];*/
if(argc < 4){
cout << "Usage: \n rc4 keyfile plaintextfile outputfile" << endl;
return -1;
}
string key;
ifstream keyfile (argv[1]);
keyfile >> k;
cout << "Key = " << k << endl;
keyfile.close();
/*ifstream plaintextf;
plaintextf.open(argv[2]);*/
ofstream ciphertextf (argv[3]);
for(int q = 0; q < 256; q++){
s[q] = q;
}
int i, j;
for(int m = 0; m < 256; m++){
j = (j + s[m] + k[m % sizeof(k)])%256;
swap(m, j, s);
}
// vector<char> bytes(plaintext.begin(), plaintext.end());
// bytes.push_back('\0');
// vector<char>::iterator it = bytes.begin();
/* char pt;
while(plaintextf.good()){
pt = plaintextf.get();
if(plaintextf.good()){
cout << pt;
ciphertextf <<(char) (pt ^ getByte());
}
} */
ifstream is;
is.open("plain");
char c;
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
// cout.flush();
}
is.close(); // close file*/
/*// plaintextf.close();
ciphertextf.close();
keyfile.close();
*/
return 0;
}
Additionally, I think the second call to is.good() [ as in if(is.good()) ], would prevent the very last character of the file from being copied.