Reputation: 11
the professor gave told us to delete a line in a txt file without the help of another file or an array, i tried to replace the line with backspace but it print the BS character instead
void rem()
{
fstream f("test.txt");
f.seekp(3, ios_base::beg);
f.write("\b",sizeof(char));
f.close();
}
1
2
3
4
5
i want to remove 2
1
3
4
5
after searching for few hours i found that everyone use another file or a vector or the try to replay the line with BS like me.
EDIT:
Solution:
void skip_line(std::fstream& f)
{
char c;
f.get(c);
f.ignore(50, '\n');
}
void getpos(int& readpos, int& writepos)
{
std::fstream f("test.txt", std::ios::in | std::ios::binary);
skip_line(f);
writepos = f.tellg();
skip_line(f);
readpos = f.tellg();
f.close();
}
void rem()
{
int writepos, readpos, length, newSize;
std::fstream f;
getpos(readpos, writepos);
f.open("test.txt");
length = readpos - writepos;
f.seekg(readpos);
for (char c; f.get(c);)
{
f.seekg(writepos);
if (c != '\n') f.put(c);
readpos++;
writepos++;
f.seekg(readpos);
}
f.close();
//fs::path p = "test.txt"
newSize = fs::file_size("test.txt") - length;
fs::resize_file("test.txt", newSize);
}
the rusult:
befor
111111
222222
333333
444444
555555
after
111111
333333
444444
555555
Upvotes: 1
Views: 869
Reputation: 117258
Backspace will not do what you hoped for. A backspace character takes up one char
just like any other character. When printed on devices capable of moving the cursor backwards, that's what'll happen. It's just a visual thing and it does not work with files.
Since you are not allowed to use another file or arrays, I'm going to assume that std::vector
s and std::string
s are also forbidden so I suggest shifting everything down in the file, one char
at a time, to overwrite the line to be removed.
You will need a function like std::getline
which is capable of reading a line from a stream into a std::string
- but you do not need to store any data so we can call it skip_line
. It could look like this:
std::istream& skip_line(std::istream& is) {
// read until reading fails or a newline is read:
for(char ch; is.get(ch) && ch != '\n';);
return is;
}
When you've opened the file, call skip_line
until you've reached the line you want to remove. If you want to remove line 2, call skip_line
1 time. If you instead want to remove line 3, call skip_line
2 times.
The get (f.tellg()
) position in the stream is now where you should start writing when you move everyting in the file back to overwrite the line to be removed. Store this position in a variable called writepos
.
Call skip_line
one time. The get position is now where you should start reading when moving the contents of the file. Store this position in a variable called readpos
.
Calculate and store the length of the line to be removed: lenght_of_line_to_be_removed = readpos - writepos
.
Now, you need to read one char
at a time from the readpos
position and write that char
to the writepos
position. It could look like this:
f.seekg(readpos); // set the _get_ position where we should read from
for(char ch; f.get(ch);) { // loop for as long as you can read a char
f.seekp(writepos); // set the _put_ position where you should write to
f.put(ch); // ...and write the char
writepos += 1; // step both positions forward
readpos += 1; // -"-
f.seekg(readpos); // set the new _get_ position
}
When the above is done, everything is "shifted down" in the file - but the size of the file will still be the same as it was before:
original: 1 2 3 4 5
after : 1 3 4 5 5
If you use C++17 or newer, you can use the standard functions std::filesystem::file_size
and std::filesystem::resize_file
to fix this. Remember that you stored lenght_of_line_to_be_removed
above. If you use a version of C++ that does not have std::filesystem
, you need to use some platform specific function. Posix systems have the truncate
function that can be used for this.
Upvotes: 2