I apologize if this doesn't make sense. I Am not sure what to google.
Lets say I have two arrays
string a_1[16];
string a_2[20];
I need to output these to a file with a function, first, a_1[0] to a_1[n].
Then reads in the a_2's.
It's also possible to run the function again to add in more a_1's and a_2's to the output file.
so the format will be:
//output_file.txt
a_1[0].....a_1[n]
a_2[0].....a_2[M]
a_1[n+1]...a_1[16]
a_2[M+1]...a_2[20]
my question is. Is there a way to read output_file.txt back so that it will read in all of the a_1's to be in order, a_1[0] to a_1[16].
and then input a_2[0] to a_2[20].
maybe just put "something" between each group so that when "something" is read, it knows to stop reading a_1's and switch to reading in for a_2....
What the OP calls "Something" is typically called a Sentinel or Canary value. To be used as a sentinel, you have to find a pattern that cannot exist in the data stream. This is hard because pretty much anything can be in a string. If you use, say, "XxXxXx" as your sentinel, then you have to be very careful that it is never written to the file.
The concept of Escape Characters (Look it up) can be used here, but a better approach could be to store a count of stored strings at the beginning of the file. Consider an output file that looks like
4
string a1_1
string a1_2
string a1_3
string a1_4
2
string a2_1
string a2_2
Read the cont, four, and then read count strings, then read for the next count and then read count more strings
OK, so you're thinking his sucks. I can't just insert a new string into a1 without also changing the number at the front of the file.
Well, good luck with inserting data into the middle of a file without totally smurfing up the file. It can be done, but only after moving everything after the insertion over by the size of the insertion, and that's not as trivial as it sounds. At the point in a programming career where this is the sort of task to which you are assigned, and you have to ask for help, you are pretty much doomed to reading the file into memory, inserting the new values, and writing the file back out again, so just go with it.
So what does this look like in code? First we ditch the arrays in favour of std::vector. Vectors are smart. They grow to fit. They know how much stuff is in them. They look after themselves so there is no unnecessary new and delete nonsense. You gotta be stupid not to use them.
Reading:
std::ifstream infile(file name);
std::vector<std::string> input;
int count;
if (infile >> count)
{
infile.ignore(); // discard end of line
std::string line;
while (input.size() < count && getline(infile, line))
{
input.push_back(line);
}
if (input.size() != count)
{
//handle bad file
}
}
else
{
// handle bad file
}
and writing
std::ofstream outfile(file name);
if(outfile << output.size())
{
for (std::string & out: output)
{
if (!outfile << out << '\n')
{
// handle write error
}
}
}
else
{
// handle write error
}
But this looks like homework, so OP's probably not allowed to use one. In that case, the logic is the same, but you have to
std::unique_ptr<std::string[]> inarray(new std::string[count]);
or
std::string * inarray = new std::string[count];
to allocate storage for the string you are reading in. The second one looks like less work than the first. Looks are deceiving. The first one looks after your memory for you. The second requires at least one delete[] in your code at the right pace to put the memory away. Miss it and you have a memory leak.
You also need to have a variable keeping track of the size of the array, because pointers don't know how big whatever they are pointing at is. This makes the write for loop less convenient.
Related
I'm a little new to using file input/output so bear with me.
I've got a function called RunList(filename), that takes the name of the file as input and returns nothing. The file will have the format of having one line that is useless and I plan on using ignore() on and then the next line which is important has the format
"i 1 2 3 4 5 ...."
where the numbers go on for a very long way, about 250000 or so.
So what I want to do is to open this file, ignore the first line, and then for each number in the file I want to use the function void insert(x, p) which is a function I have defined to insert x after the current iterator position p. The end result is that I want to have my list contain all of the numbers in the file after the "i" and be in the same order. I have also defined the functions ListItr find(x) and ListItr first() which will return the iterator to the position that views x and to the first potion respectively.
Could anyone provide me with a means of doing this? I was thinking of using a for() loop and taking in each word at a time from the file and using my function to insert each element, but I'm a little lost as to how to do this, as I said I'm very new to using file input/output.
So, my RunList function currently looks something like this, although obviously its not finished nor does it really work, hence me needing some help on it.
void Runlist(filename){
ifstream in;
in.open(filename);
in.ignore(1000, '\n'); //this is me trying to ignore the first line
for (int i, i < 250000, i++){
int number;
in >> number
void insert(number, i)
}
}
But the plan was, I select the file, ignore the first line, then set up a for loop where i can use my void insert(number, i) to insert each number, but then i don't really understand how to read in each word at a time, or to preserve the order because if I just kept using the function on each number over and over then the list would have the numbers in the reverse order I believe.
There are several issues in your code:
You do not specify void for the return type of the function.
Instead of ignore, you could just drop the first line when reading by using getline once.
Your for loop usage is also pretty invalid: commas instead of semi-colons
No initialization of i, and so on.
insert is not shown, but you could probably use append anyway since that is what you seem to be doing.
i is not an "iterator" either, so probably you meant index.
You are having a function declaration in the middle of the function rather than calling it.
This pseudo code should get you going about understanding the input file stream class and its usage for this in C++:
void Runlist(filename)
{
ifstream in(filename, ifstream::in);
in.getline(0, 1024);
int number;
while (in >> number)
append(number);
in.close();
}
Disclaimer: this pseudo code is missing proper error checking, and so on.
So I am writing my own custom FTP client for a school project. I managed to get everything to work with the swarming FTP client and am down to one last small part...reading the .part files into the main file. I need to do two things. (1) Get this to read each file and write to the final file properly (2) The command to delete the part files after I am done with each one.
Can someone please help me to fix my concatenate function I wrote below? I thought I had it right to read each file until the EOF and then go on to the next.
In this case *numOfThreads is 17. Ended up with a file of 4742442 bytes instead of 594542592 bytes. Thanks and I am happy to provide any other useful information.
EDIT: Modified code for comment below.
std::string s = "Fedora-15-x86_64-Live-Desktop.iso";
std::ofstream out;
out.open(s.c_str(), std::ios::out);
for (int i = 0; i < 17; ++i)
{
std::ifstream in;
std::ostringstream convert;
convert << i;
std::string t = s + ".part" + convert.str();
in.open(t.c_str(), std::ios::in | std::ios::binary);
int size = 32*1024;
char *tempBuffer = new char[size];
if (in.good())
{
while (in.read(tempBuffer, size))
out.write(tempBuffer, in.gcount());
}
delete [] tempBuffer;
in.close();
}
out.close();
return 0;
Almost everything in your copying loop has problems.
while (!in.eof())
This is broken. Not much more to say than that.
bzero(tempBuffer, size);
This is fairly harmless, but utterly pointless.
in.read(tempBuffer, size);
This the "almost" part -- i.e., the one piece that isn't obviously broken.
out.write(tempBuffer, strlen(tempBuffer));
You don't want to use strlen to determine the length -- it's intended only for NUL-terminated (C-style) strings. If (as is apparently the case) the data you read may contain zero-bytes (rather than using zero-bytes only to signal the end of a string), this will simply produce the wrong size.
What you normally want to do is a loop something like:
while (read(some_amount) == succeeded)
write(amount that was read);
In C++ that will typically be something like:
while (infile.read(buffer, buffer_size))
outfile.write(buffer, infile.gcount());
It's probably also worth noting that since you're allocating memory for the buffer using new, but never using delete, your function is leaking memory. Probably better to do without new for this -- an array or vector would be obvious alternatives here.
Edit: as for why while (infile.read(...)) works, the read returns a reference to the stream. The stream in turn provides a conversion to bool (in C++11) or void * (in C++03) that can be interpreted as a Boolean. That conversion operator returns the state of the stream, so if reading failed, it will be interpreted as false, but as long as it succeeded, it will be interpreted as true.
I am having a file which stores ints in binary format. And I am writing a function in C++ which takes int data and inserts it to a specific position in file.
void AddData(int position, int data);
position is the index at which data has to inserted.
data is the int value to be inserted.
code
void AddData(int position, int data)
{
fstream os;
char buff[4096];
cnt1 = position;
cnt2+=(data_cnt-cnt1); // data_cnt is global var to cout the no. of data items
os.open("edata.dat", ios::out | ios::in | ios::binary );
os.seekg(0); // start from beg
os.seekg(cnt1*sizeof(int)); // move to position at which data has to be inserted
os.read(reinterpret_cast<char*>(buff), cnt2*sizeof(int)); // read rest of file
os.seekg(cnt1*sizeof(int)); // move back to previous position
cout << os.tellg();
os.write( reinterpret_cast<char*>(&data), sizeof(int) ); //add data
os.write(reinterpret_cast<char*>(buff), cnt2*sizeof(int)); //write back the read data
data_cnt++;
}
when function is called first time, it shows data item is added twice. And when function is called 2nd time, tellg() shows -1.
can't figure out, whats going wrong?
Honestly, I can't see what's wrong either but - forgive me for being that straigforward - your coding style doesn't help !!
There are a lot of things which are wrong in my opinion, in your example :
you use a global variable to count the number of items.
you assume there won't be more than 4096 bytes in the remainder part
your reinterpret_cast is completely unnecessary (writing 'buff' is the same as writing '&buff[0]' and gives you a char* directly)
you don't do any check whatsoever (is position beyond the end of the file for example
?)
Honestly even if you make this code work, every person who has to maintain it will really hate you. (I'm sorry to sound mean but I had to maintain loads of such code in the past and that's a nighmare if something, somewhere suddenly doesn't work because you switched to a 64bit os ;) )
Enough lecturing, time for suggestions :
Why not, simply, do the following :
copy the source file from the begining to 'position' (and check position is in the boundaries of the file !) to a temp file.
write your int to your temp file
copy the source file (from position+1 to eof), to temp file (from position + 2)
erase the edata.dat, rename temp to edata.dat
It's much easier, safer, cleaner and probably as fast . Most importantly : if something wrong happens before the end, you still have your edata.dat in a stable, uncorrupted state.
Hope it helps
From what I can tell, cnt2 is meant to represent the number of ints after the int being inserted, right?
In which case it should be cnt2 = data_cnt-cnt1, not cnt2 += data_cnt-cnt1. You should probably make those local variables, as they don't need to store anything between calls.
The first time you call the function, you're probably getting cnt2 having the correct value by coincidence. On the second call, it's being set to double the correct value (because you're incrementing), so the read is failing, and the stream is going into an error state.
I'm not sure why the data might be added twice though. Perhaps if you fix the cnt2 bug, it might just start working.
I have the following problem. I have to implement a class that has an attribute that is a char pointer meant to point to the object's "code", as follows:
class foo{
private:
char* cod;
...
public:
foo();
void getVal();
...
}
So on, so forth. getVal() is a method that takes the code from the standard istream and fills in all the information, including the code. The thing is, the "code" that identifies the object can't be longer than a certain number of characters. This has to be done without using customized buffers for the method getVal(), so I can't do the following:
//suppose the maximum number of characters is 50
void foo::getVal()
{
char buffer[100];
cin >> buffer;
if (strlen(buffer) > 50) //I'm not sure this would work considering how the stream
of characters would be copied to buffer and how strlen
works, but suppose this tells me how long the stream of
characters was.
{
throw "Exception";
}
...
}
This is forbidden. I also can't use a customized istream, nor the boost library.
I thought I could find the place where istream keeps its information rather easily, but I can't find it. All I've found were mentions to other types of stream.
Can somebody tell me if this can be done or where the stream keeps its buffered information?
Thanks
yes using strlen would work definitely ..you can write a sample program
int main()
{
char buffer[10];
std::cout << "enter buffer:" ;
std::cin >>buffer;
if(strlen(buffer)>6)
std::cout << "size > 6";
getch();
}
for inputs greater than size 6 characters it will display size >6
uhm .... >> reads up to the first blank, while strlen counts up to the first null. They can be mixed if you know for sure no blanks are in the middle of string you're going to read and that there are no more than 100 consecutive characted. If not, you will overrun the buffer before throwing.
Also, accessing the buffer does not grant all the string to be already there (the string can go past the buffer space, requiring to partially read and refill the buffer...)
If blanks are separator, why not just read into an std::string, and react to its final state? All the dynamics above are already handled inside >> for std::string.
[EDIT after the comments below]
The only way to store a sequence of unknown size, is to dynamically allocate the space and make it grow as it is required to grow. This is, no more - no less, what sting and vector do.
Whether you use them or write your own code to allocate and reallocate where more space is required, doesn't change the substance.
I'm start thinking the only reason of those requirements is to see your capability in writing your own string class. So ... just write it:
declare a class holding a pointer a size and a capacity, allocate some space, track how much you store, and when no store is available, allocate another wider store, copy the old, destroy it, and adjust the data member accordingly.
Accessing directly the file buffer is not the way, since you don't control how the file buffer is filled in.
An istream uses a streambuf.
I find that www.cppreference.com is a pretty good place for quick C++ references. You can go there to see how to use a streambuf or its derivative filebuf.
I have a function that swaps two chars, in a file, at a time, which works, however if i try to use the function more than once the previous swap i made will be wiped from the text file and the original text in now back in, therefore the second change will seem as my first. how can i resolve this?
void swapping_letters()
{
ifstream inFile("decrypted.txt");
ofstream outFile("swap.txt");
char a;
char b;
vector<char> fileChars;
if (inFile.is_open())
{
cout<<"What is the letter you want to replace?"<<endl;
cin>>a;
cout<<"What is the letter you want to replace it with?"<<endl;
cin>>b;
while (inFile.good())
{
char c;
inFile.get(c);
fileChars.push_back(c);
}
replace(fileChars.begin(),fileChars.end(),a,b);
}
else
{
cout<<"Please run the decrypt."<<endl;
}
for(int i = 0; i < fileChars.size(); i++)
{
outFile<<fileChars[i];
}
}
What you probably want to do is to parameterize your function :
void swapping_letters(string inFileName, string outFileName)
{
ifstream inFile(inFileName);
ofstream outFile(outFileName);
...
Because you don't have parameters, calling it twice is equivalent to:
swapping_letters("decrypted.txt", "swap.txt");
swapping_letters("decrypted.txt", "swap.txt");
But "decrypted.txt" wasn't modified after the first call, because you don't change the input file. So if you wanted to use the output of the first operation as the input to the second you'd have to write:
swapping_letters("decrypted.txt", "intermediate.txt");
swapping_letters("intermediate.txt", "swap.txt");
There are other ways of approaching this problem. By reading the file one character at a time, you are making quite a number of function calls...a million-byte file will involve 1 million calls to get() and 1 million calls to push_back(). Most of the time the internal buffering means this won't be too slow, but there are better ways:
Read whole ASCII file into C++ std::string
Note that if this is the actual problem you're solving, you don't actually need to read the whole file into memory. You can read the file in blocks (or character-by-character as you are doing) and do your output without holding the entire file.
An advanced idea that you may be interested in at some point are memory-mapped files. This lets you treat a disk file like it's a big array and easily modify it in memory...while letting the operating system worry about details of how much of the file to page in or page out at a time. They're a good fit for some problems, and there's a C++ platform-independent API for memory mapped files in the boost library:
http://en.wikipedia.org/wiki/Memory-mapped_file