Merging two text files gives wierd results - c++

I need to merge two text files by putting them in a vector array and then writing them in a new text file.
After merging them.The new file has extra characters.
FE:
f1.txt ("text1")
f2.txt ("text2.")
f12.txt ("text1˙text2.˙W64")
Content of the buffer: "text1 text2. W64"
Here is the code:
int main(){
enum errorcode{FNF,FNC};
vector<char> buffer;
char ime[255];
cin>>ime;//first file
ifstream ud1(ime,ios::in);
if(ud1.is_open()){
while(!ud1.eof())buffer.push_back(ud1.get());
ud1.close();
}
else {cout<<"File not found.";return FNF;}
cin>>ime;//second file
ifstream ud2(ime,ios::in);
if(ud2.is_open()){
while(!ud2.eof())buffer.push_back(ud2.get());
ud2.close();
}
else {cout<<"File not found.";return FNF;}
cin>>ime;//new file
ofstream id(ime,ios::out);
if(id.is_open()){
for(int i=0;i<buffer.capacity();i++)id.put(buffer[i]);
id.close();
}
else {cout<<"File not created.";return FNC;}
return 0;
}
I guess this is because of notepad or files themselves.
Can you please tell me reason for this.

you are using Vector capacity: Returns the size of the storage space currently allocated for the vector, expressed in terms of elements.
You must use vector size: Returns the number of elements in the vector. This is the number of actual objects held in the vector, which is not necessarily equal to its storage capacity.
About the ˙
please look at istream::get return value:
Return Value
The first signature returns the character read, or the end-of-file value (EOF) if no characters are available in the stream (note that in this case, the failbit flag is also set).
So, you could change the loop to this:
while(!ud1.eof()){
int tmpChar = ud1.get();
if( !ud1.eof() )
buffer.push_back(tmpChar);
}

Related

Reading lines of txt file into array prints only the last element

First of all, I didn't code in C++ for more then 8 years, but there is a hobby project I would like to work on where I ran into this issue.
I checked a similar question: Only printing last line of txt file when reading into struct array in C
but in my case I don't have a semicolon at the end of the while cycle.
Anyway, so I have a nicknames.txt file where I store nicknames, one in each line.
Then I want to read these nicknames into an array and select one random element of it.
Example nicknames.txt:
alpha
beta
random nickname
...
Pirate Scrub
Then I read the TXT file:
int nicknameCount = 0;
char *nicknames[2000];
std::string line;
std::ifstream file("nicknames.txt");
FILE *fileID = fopen("asd.txt", "w");
while (std::getline(file, line))
{
nicknames[nicknameCount++] = line.data();
// (1)
fprintf(fileID, "%i: %s\n", nicknameCount - 1, nicknames[nicknameCount - 1]);
}
int randomNickIndex = rand() % nicknameCount;
// (2)
for (int i = 0; i < nicknameCount; i++)
fprintf(fileID, "%i: %s\n", i, nicknames[i]);
fprintf(fileID, "Result: %s\n", nicknames[randomNickIndex]);
fprintf(fileID, "Result: %i\n", randomNickIndex);
fclose(fileID);
exit(0);
What then I see at point (1) is what I expect; the nicknames. Then later at point (2) every single member of the array is "Pirate Scrub", which is the last element of the nicknames.txt.
I think it must be something obvious, but I just can't figure it out. Any ideas?
line.data() returns a pointer to the sequence of characters. It is always the same pointer. Every time you read a new line, the contents of line are overwritten. To fix this, you will need to copy the contents of line.
Change:
char *nicknames[2000];
to
char nicknames[2000][256];
and
nicknames[nicknameCount++] = line.data();
to
strcpy(nicknames[nicknameCount++], line.data());
However, using a vector to store the lines is probably better, since this is C++
Your nicknames array does not contain copies of the strings, all the nicknames are pointers to the same data owned by line.
Instead of char* nicknames[2000] i would recommend you use
std::vector<std::string> nicknames;
and then inside the loop:
nicknames.push_back(line);
This:
char *nicknames[2000];
is an array of 2000 pointers to char. Nowhere in your code you are actually storing the strings from the file. This
nicknames[nicknameCount++] = line.data();
merely stores pointers to the lines internal buffer in the array. In the next iteration this buffer is overwritten with contents of the next line.
Forget about all the C i/o. Mixing C and C++ is advanced and you don't need it here. If you want to store a dynamically sized array of strings in C++, that is a std::vector<std::string>:
std::vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
Also for writing to the output file you should use an std::ofstream.

how to reverse order of lines in a file [duplicate]

This question already has answers here:
How can I reverse the order of lines in a file?
(24 answers)
Closed 8 years ago.
How can we revere order of lines in a file not the lines themselves.
File can get huge.
No assumption should be made about the length of a line.
Input:
this is line1
this is line2
this is line3
Example Output:
this is line3
this is line2
this is line1
I though of making use of another file as buffer, like a stack data structures, but could not really go anywhere with it.
Any thoughts on this ?
Read in large blocks of the file starting at both ends. Inside those blocks, swap the first line for the last line and then move both pointers to keep track of where you are. Write out each block as you fill it. When the two pointers meet in the middle, you are done.
Don't try to modify the blocks in place, that will make things more complicated. Use four blocks, the first read block, the first write block, the last read block, and the last write block. As each write block is complete, write it out. As each read block is exhausted, read in another one. Be careful not to overwrite anything you've not yet read!
It should be fairly straightforward, just tedious. If you don't need it to be optimal, you can just read blocks backwards and write out a new file and then move it on top of the existing file.
If the file won't fit in memory, then it's a two-pass process. The first pass, you read chunks of the file (as many lines as will fit into memory), and then write them to a temporary file in reverse order. So you have:
while not end of input
read chunk of file into array of lines
write lines from array to temporary file, in reverse order
end while
When you're done with the first pass, you'll have a bunch of temporary files: temp1.txt, temp2.txt, temp3.txt ... tempN.txt.
Now open the last file (tempN.txt) for append, and start appending the files in reverse order. So you have:
open fileN for append
fileno = N-1
while fileno > 0
append file_fileno to fileN
fileno--
end while
Then rename tempN.txt and delete the other temporary files.
By the way, you can use the operating system supplied concatenation utility for step 2. On Windows, for example, you could replace step 2 with:
copy /A file4.txt+file3.txt+file2.txt+file1.txt mynewfile.txt
There are similiar utilities on other platforms.
You might run into command line length limitations, though.
it can be done in 2 simple steps:
step 1: reverse all the file
step 2: reverse each line
step:0 1 2
---------------------
abc zyx xyz
1234 => 4321 => 1234
xyz cba abc
EDIT: here is a complete solution:
#include <iostream>
#include <fstream>
#include <algorithm>
#define BUFFSIZE 4098 /*make sure this is larger then the longest line...*/
using namespace std;
bool reverse_file(const char* input, const char* output)
{
streamsize count=0;
streamoff size=0,pos;
char buff[BUFFSIZE];
ifstream fin(input);
ofstream fout(output);
if(fin.fail() || fout.fail()){
return false;
}
fin.seekg(0, ios::end);
size = fin.tellg();
fin.seekg(0);
while(!fin.eof()){
fin.read(buff, BUFFSIZE);
count = fin.gcount();
reverse(buff,buff+count);
pos = fin.tellg();
if(pos<0) {
pos = size;
}
fout.seekp(size - pos);
fout.write(buff,count);
}
return true;
}
bool reverse_file_lines(const char* input, const char* output)
{
streamsize count=0;
char buff[BUFFSIZE];
ifstream fin(input);
ofstream fout(output);
if(fin.fail() || fout.fail()){
return false;
}
while(!fin.eof()){
fin.getline(buff, BUFFSIZE);
/*if BUFFSIZE is smallest then line size gcount will return 0,
but I didn't handle it...*/
count = fin.gcount();
if(buff[count-1]==0)count--;
reverse(buff,buff+count);
fout.write(buff,count);
if(!fin.eof()){
fout<<endl;
}
}
return true;
}
int main()
{
reverse_file("test.in", "test.tmp");
reverse_file_lines("test.tmp","test.out");
return 0;
}

C++ Reading from a text file into a const char array

I want to read in lines from a text file into a 2-d char array but without the newline character.
Example of .txt:
TCAGC
GTAGA
AGCAG
ATGTC
ATGCA
ACAGA
CTCGA
GCGAC
CGAGC
GCTAG
...
So far, I have:
ifstream infile;
infile.open("../barcode information.txt");
string samp;
getline(infile,samp,',');
BARCLGTH = samp.length();
NUMSUBJ=1;
while(!infile.eof())
{
getline(infile,samp,',');
NUMSUBJ++;
}
infile.close(); //I read the file the first time to determine how many sequences
//there are in total and the length of each sequence to determine
//the dimensions of my array. Not sure if there is a better way?
ifstream file2;
file2.open("../barcode information.txt");
char store[NUMSUBJ][BARCLGTH+1];
for(int i=0;i<NUMSUBJ;i++)
{
for(int j=0;j<BARCLGTH+1;j++)
{
store[i][j] = file2.get();
}
}
However, I do not know how to ignore the newline character. I want the array to be indexed so that I can access a sequence with the first index and then a specific char within that sequence with the second index; i.e. store[0][0] would give me 'T', but I do not want store[0][5] to give me '\n'.
Also, as an aside, store[0][6], which I think should be out of bounds since BARCLGTH is 5, returns 'G',store[0][7] returns 'T',store[0][8] returns 'A', etc. These are the chars from the next line. Alternatively, store[1][0],store[1][1], and store[1][2] also return the same values. Why does the first set return values, shouldn't they be out of bounds?
As you're coding in C++, you could do like this instead:
std::vector<std::string> barcodes;
std::ifstream infile("../barcode information.txt");
std::string line;
while (std::getline(infile, line))
barcodes.push_back(line);
infile.close();
After this the vector barcodes contains all the contents from the file. No need for arrays, and no need to count the number of lines.
And as both vectors and strings can be indexed like arrays, you can use syntax such as barcodes[2][0] to get the first character of the third entry.

C++: Reading and Sorting Binary Files

I've been scratching my head and putting this homework off for a couple days but now that I hunker down to try and do it I'm coming up empty. There's 4 things I need to do.
1) Read a binary file and place that data into arrays
2) Sort the list according to the test scores from lowest to highest
3) Average the scores and output it
4) Create a new binary file with the sorted data
This is what the binary data file looks unsorted
A. Smith 89
T. Phillip 95
S. Long 76
I can probably sort since I think I know how to use parallel arrays and index sorting to figure it out, but the reading of the binary file and placing that data into an array is confusing as hell to me as my book doesn't really explain very well.
So far this is my preliminary code which doesn't really do much:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <Windows.h>
using namespace std;
int get_int(int default_value);
int average(int x, int y, int z);
int main()
{
char filename[MAX_PATH + 1];
int n = 0;
char name[3];
int grade[3];
int recsize = sizeof(name) + sizeof(int);
cout << "Enter directory and file name of the binary file you want to open: ";
cin.getline(filename, MAX_PATH);
// Open file for binary write.
fstream fbin(filename, ios::binary | ios::in);
if (!fbin) {
cout << "Could not open " << filename << endl;
system("PAUSE");
return -1;
}
}
Sorry for such a novice question.
edit: Sorry what the data file stated earlier is what it SHOULD look like, the binary file is a .dat that has this in it when opened with notepad:
A.Smith ÌÌÌÌÌÌÌÌÌÌÌY T. Phillip ÌÌÌÌÌÌÌÌ_ S. Long ip ÌÌÌÌÌÌÌÌL J. White p ÌÌÌÌÌÌÌÌd
Reading a file in c++ is simple:
create a stream from file [so that to read from the stream] (you have filestream[input/output], stringstream ... )
ifstream fin; //creates a fileinput stream
fin.open(fname.c_str(),ifstream::binary); // this opens the file in binary mod
void readFile(string fname)
{
ifstream fin;
fin.open(fname.c_str()); //opens that file;
if(!fin)
cout<<"err";
string line;
while(getline(fin,line)) //gets a line from stream and put it in line (string)
{
cout<<line<<endl;
//reading every line
//process for you need.
...
}
fin.close();
}
as you specify, the file is simply a text file, so you can process each line and do whatever you want.
Reading from a binary file may seem confusing, but it is really relatively simple. You have declared your fstream using your file name and set it to binary, which leaves little to do.
Create a pointer to a character array (typically called a buffer, since this data is typically extracted from this array after for other purposes). The size of the array is determined by the length of the file, which you can get by using:
fbin.seekg(0, fbin.end); //Tells fbin to seek to 0 entries from the end of the stream
int binaryLength = fbin.tellg(); //The position of the stream (i.e. its length) is stored in binaryLength
fbin.seekg(0, fbin.beg); //Returns fbin to the beginning of the stream
Then this is used to create a simple character array pointer:
char* buffer = new char[binaryLength];
The data is then read into the buffer:
fbin.read(buffer, binaryLength);
All the binary data that was in the file is now in the buffer. This data can be accessed very simply as in a normal array, and can be used for whatever you please.
The data you have, however, does not at all seem binary. It looks more like a regular text file. Perhaps, unless explicitly stated, you ought to consider a different method for reading your data.
You know, with that low range of sorting index you can avoid actual sorting (with comparing indices and moving data forth and back). All you have to do is to allocate a vector of vector of strings, resize it to 101. Then traverse the data, storing each: "A. Smith" in 89-th element; "T. Phillip" in 95-th; "S. Long" in 76-th and so on.
Then by iterating the vector elements from begin() to end() you would have all the data already sorted.
It's almost linear complexity (almost, because allocation/resizing of subvectors and strings can be costly) easy and transparent.

Problems with storing data into the array

My programs allows user to delete specify records when they input a username. When they pass in the name, it will invoke a method which will store them into a array, and write them back to the file without appending, so as to re-write the file.
But there is some problem during the storing part where my last line of the textfile is not stored properly, and instead it copy from the 2nd last line and copy to the last line with the name included.
Hopefully no1 will get confuse :/. The example of the textfile and data stored inside my array is below which i make bold and italic for clearer picture, and also method for the deleteRec.
This is what my textfile contains.
user;pass;1234;John;1111
user1;pass1;2345;May;2222
user2;pass2;3456;Mary;3333
user3;pass3;4567;Andy;4444
hr;hr;5678;Jonathan;5555
admin;admin;6789;Aili;6666
user10;pass10;7890;eggy;9999
user11;pass11;9807;Mary;7777
This is my output when i run my program to delete.
Data stored in store[] array: user1;pass1;2345;May;2222
Data stored in store[] array: user2;pass2;3456;Mary;3333
Data stored in store[] array: user3;pass3;4567;Andy;4444
Data stored in store[] array: hr;hr;5678;Jonathan;5555
Data stored in store[] array: admin;admin;6789;Aili;6666
Data stored in store[] array: user10;pass10;7890;eggy;9999
***Data stored in store[] array: ;pass10;7890;eggy;9999***
Data stored in store[] array:
bool Employee::deleteRec(string nm)
{
int count;
int i=0;//for looping
ifstream file("login1.txt");
string fusername,empty;
string store[100];//initialize a array to store textfile contents
while (!file.fail())
{
getline(file,fusername,';');// use ; as delimiter
getline(file,empty);// use line end as delimiter, and to skip the rest of the information
string add="";//initialize add string to nothing when it loops
add += fusername+';'+empty; //adds back the username and rest of the line together back
if(fusername!=nm)//to check if the username in textfile do not match the user input name
{
store[i]=add; //store into an array
cout<<"i is: "<<i<<endl;
cout<<"store array[] = "<<store[i]<<endl;
i++;
}
else{}
}
//ofstream pwd2_file ("login1.txt", ios::app); //suppose to user this if im writing to file
for(int x=0;x<i+1;x++)
{
cout<<"Data stored in store[] array: "<<store[x]<<endl;
}
return false;
}
The problem with your loop is that when you reach end of file, your stream will not have failed yet. It only fails on the next read but you are not verifying this.
Therefore your array is containing the last record twice.
That you have an empty string as the first field could be because it set this one empty to read into it, (stream wasn't yet in a failed state) or because there was an empty line at the end of your input file which got read in.
Create a struct for your user and its data, and read in from the stream. If the whole of this read succeeds, you can append to your dataset.
I would suggest you use std::vector for this and push_back().
The correct way to loop is as follows:
struct EmployeeData
{
std::string name;
// fill in members
;
std::istream& operator>>( std::istream& is, EmployeeData& emp )
{
std::getline( is, emp.name(), ';' );
// etc.
return is;
}
std::vector< EmployeeData > emps;
EmployeeData emp;
while( is >> emp )
{
emps.push_back( emp );
}
I'd recommend using a debugger and just figure out what is getting passed over. Looks like an off by one error either in where the output is stored in the array, or when it is rewritten to the file. Would explain your lack of boundary users.