Override a file and truncate the non-overridden part - c++

How would I overwrite the contents of a file and truncate the parts of the file that were not overwritten using C++? Specifically, I use a temporary file to hold an edited copy of the original data and want to overwrite the original file with the new data, and truncate the rest of the original file.
For code in question: https://github.com/Sparen/DanmakufuObfuscator/blob/master/dnhobf_fxn.cc
(RemoveSingleLineComments(FILE* infile))
For clarification, this is what I want to do:
Let's say the original is ABCDEFGHIJK. I want to remove B, D, H, and J, resulting in ACEFGIK. I copy this back, and end up with ACEFGIKHIJK. I want to remove that last HIJK

Don't write to the same file as you read. Instead:
Open file.txt for reading.
Open file.txt.new for writing.
Read a line from file.txt, perform your map/filter operations, and write the result to file.txt.
Repeat step 3 until EOF.
Close the files.
Rename file.txt.new over file.txt.
The benefit over working in place is that you won't end up with garbage if your program crashes or you lose power. As a rule, I only open files either:
that do not exist yet
in append mode (for logs)

Open the original file as an fstream. Once the temporary file has everything it needs to, close the original file. Reopen the original file with out and trunc modes, and write back to it.
This allows you to basically paste the contents of the temporary file onto a blank slate with the same filename and extension.

Related

Insert in a file without overwriting without using a 2nd file using C/C++

The below are the contents in a text file.
name1: 1234
name2: 2000
name3: 3000
This is an existing text file and I want to replace one value(say 1234) with another value (say 12345) in the text file. so I placed the cursor at start of the value (here its the 7th position) . Then i used the following statement:
fprintf(filepointer,"12345\n");
The resultant file is like
name1: 12345
ame2 : 2000
name3 : 3000
Its overwriting the 4 characters("1000") and a newline('\n') and 'n' with 5 characters("12345") and a newline('\n').
The solutions I know are:
1. Overwriting the entire file to add one extra character.
2. Copying each line in a linked list node and change the characters in the memory and write in the same file.
3. Create a temp file and copy the new characters to the desired place in the temp file and change the name of the temp file to source file name and delete the source file.
Also I tried adding carriage return '\r' and windows format of EOF ('\r\n') , still the next line characters are overwritten. Also I expanded the file size using [SetEndOfFile][1] API and still I face the same problem. I searched many forums and found answers like "It is not possible to insert characters without overwriting".
Is there any solution just to insert characters without overwriting the characters in the middle of the file. or any logic to insert characters in a line and not affect the next line.
Thanks in advance.
Is it possible Using visual studio VC++ ??
Thanks:)
A sequential file is ehh... just sequential. All the bytes follow each other with no notion of line or any other structure.
The only operations allowed by the underlying file system are (only speaking of writing):
replace bytes anywhere in the file
add bytes at the end of the file
truncate the file (or add random(*) bytes at the end by moving the end of file
There is no provision for insertion in the middle so no language will be able to do that (except by doing overwriting under the hood)
(*) if you move the end of file forward more than one logical block (file system sense) many file systems will create a hole that is a phantom block that does not use any space on disk and is read as null bytes
Is there any solution just to insert characters without overwriting
the characters in the middle of the file. or any logic to insert
characters in a line and not affect the next line.
No, what you ask for is not possible with any file system I've ever used.
Use method (3), a temp file. Use a temp file with a different, unique extension added/replaced, eg '.tmp', so that the temp files can be recognised on startup, then:
1) Get source file name, eg. 'source.txt'
2) Append, or replace a '.tmp' extension: 'source.txt.tmp'
3) Open the two files
4) Read the source, modify, write the temp
5) Close both
6) Delete source file
7) rename temp file
When you program starts:
1) search for files with '.tmp' extension.
2) if found, eg. 'source.txt.tmp', take the file name and remove the extension, eg 'source.txt'
3) Test if a file with that name exists
4) If so, delete the temp file
5) If not, rename the temp file
Result: if the process crashes, you end up with either an intact, unmodified source file, or an intact, modified source file.

How do i write to a specific line of a text file?

myfile<<hashdugumu[key].numara;
I have this piece of code.For example,i would like to write to eighth line.How do i do that in c++ ?Thanks in advance.
If the line you want to write is exactly the same length (in bytes, not in characters, remember some encodings (like e.g. UTF-8) is variable length) then it's very easy: Just skip over the first seven lines and then write the line.
There is a caveat with this though: input streams and output streams have different stream positions. So if you read from a combined input/output file stream then only the read position will change, so if you just try to write directly then you will not write at the same position. To solve this you need to get the read position, and set the write position to the same value.
As an alternative, or if the data you want to write is not the same size as the existing data, then you have to use a temporary "buffer", be it another file or an actual in-memory buffer.
If the file is not big you can use an in-memory buffer, for example using a std::vector for the lines. Read each line into the vector, and then modify the lines (elements in the vector) that you want to modify. Finally reopen the file for writing, truncating it, and then just write each "line" to the file.
There is a slight problem with the above though when it comes to the rewriting of the data, and that is if the file is truncated and then there's an error when you write to the file, you can lose data. This can be dsolved by using a temporary file.
Using a temporary file it's easier to not bother with the in-memory buffer, and instead read from the original file and write directly to the temporary file. Knowing when you should write something else is done by keeping track of the current line numbers, which is easy if you read one line at a time. In your example you read the first seven lines from the original file and write them to the temporary file, after the seventh line you write your special eight line while skipping the original eight line from the original file, and then just continue reading/writing the remaining lines. When done close the files and then rename the temporary file as the original file.

how to delete the last line in a text file with 100M lines without having to rewrite the whole file?

Suppose I have a really large text file, say 100 million lines or 1 GB and I want to delete the last line. Is there anyway to do this without having to rewrite 99,999,999 lines to a new file and delete the old one? Suppose the file is really really large that the rewrite option is prohibitively expensive. What would you do to delete the last line then? Thank you.
You can open the file, read from the end backwards until you find the first line delimiter (normally LF or CR/LF, depending on platform), calculate the file offset at that point, and truncate the file to that file offset.
You should use a truncation function, but neither FILE* nor iostream support it.
However, there are usually OS-specific functions at the lower level to truncate a file.
If Unix, you may use ftruncate, but you'll need to find the offset where you want to truncate first (does each line have a fixed size?).
Be careful that, if you have opened a FILE* for finding the offset, you need to be sure to synchronize it with the lower level. You may simply fclose the file, then reopen it with open for the ftruncate of the file at the decided offset.
Similar questions: https://stackoverflow.com/a/873653/2741329 and https://stackoverflow.com/a/15154682/2741329

What is the difference between a and a+ option in fopen function?

I can't understand the description of the "a" and "a+" option in the C fopen api documentation. The option in "a+" is append and update. What is the meaning of the word update here?
Here is what the man pages (man fopen) say:
a
Open for appending (writing at end of file). The file is created if it
does not exist. The stream is positioned at the end of the file.
a+
Open for reading and appending (writing at end of file). The file is
created if it does not exist. The initial file position for reading is
at the beginning of the file, but output is always appended to the end
of the file.
Which means:
for a+:
pointer initially is at the start of the file ( for reading ) but when a write operation is attempted it is moved to the end of the file.
Yes, there is an important difference:
a: append data in a file, it can update the file writing some data at the end;
a+ : append data in a file and update it, which means it can write at the end and also is able to read the file.
In a pratical situation of only writing a log both are suitable, but if you also need to read something in the file (using the already opened file in append mode) you need to use "a+".

How to overwrite only part of a file in c++

I want to make modifications to the middle of a text file using c++, without altering the rest of the file. How can I do that?
Use std::fstream.
The simpler std::ofstream would not work. It would truncate your file (unless you use option std::ios_base::app, which is not what you want anyway).
std::fstream s(my_file_path); // use option std::ios_base::binary if necessary
s.seekp(position_of_data_to_overwrite, std::ios_base::beg);
s.write(my_data, size_of_data_to_overwrite);
If the replacement string is the same length, you can make the change in place. If the replacement string is shorter, you may be able to pad it with zero-width spaces or similar to make it the same number of bytes, and make the change in place. If the replacement string is longer, there just isn't enough room unless you first move all remaining data.
Generally, open the file for reading in text mode, read line after line until the place you want to change, while reading the lines, write them in a second text file you opened for writing. At the place for change, write to the second file the new data. Then continue the read/write of the file to its end.