When you open a .txt file with fopen
Is there any way to delete some strings in a file without rewriting.
For example this is the txt file that i will open with fopen() ;
-------------
1 some string
2 SOME string
3 some STRING
-------------
i want to delete the line which's first character is 2 and change it into
-------------
1 some string
3 some STRING
-------------
My solution is;
First read all data and keep them in string variables. Then fopen the same file with w mode. And write the data again except line 2. (But this is not logical i am searching for an easier way in C ...)
(i hope my english wasn't problem)
The easiest way might be to memory-map the whole file using mmap. With mmap you get access to the file as a long memory buffer that you can modify with changes being reflected on disk. Then you can find the offset of that line and move the whole tail of the file that many bytes back to overwrite the line.
you should not overwrite the file, better is to open another (temp)-file, write contents inside and then delete old file and rename the file. So it is safer if problems occur.
I think the easiest way is to
read whole file
modify contents in memory
write back to a temp file
delete original file
rename temp file to original file
Sounds not too illogical to me..
For sequential files, no matter what technique you use to delete line 2, you still have to write the file back to disk.
Related
Is it possible to write at the middle of a file for example I want to insert some string at the 5th position in the 2nd line of a file in c ?
I'm not very familiar with some of C functions that are related to handling files , if someone could help me I would appreciate it
I tried using fputs but I couldn't insert characters at the desired location
open a new output file
read the input file line by line (fgets) writing each line out to a new file as you read.
When you hit the place you want to insert write the new line(s)
The carry on copy the old lines to the new file
close input and output
rename output file to input
Continuing from my comments above. Here's what I'd do:
Create two large, static char[] buffers of the same size--each large enough to store the largest file you could possibly ever need to read in (ex: 10 MiB). Ex:
#define MAX_FILE_SIZE_10_MIB (10*1024*1024)
static char buffer_file_in[MAX_FILE_SIZE_10_MIB];
static char buffer_file_out[MAX_FILE_SIZE_10_MIB];
Use fopen(filename, "r+") to open the file as read/update. See: https://cplusplus.com/reference/cstdio/fopen/. Read the chars one-by-one using fgetc() (see my file_load() function for how to use fgetc()) into the first large char buffer you created, buffer_file_in. Continue until you've read the whole file into that buffer.
Find the location of the place you'd like to do the insertion. Note: you could do this live as you read the file into buffer_file_in the first time by counting newline chars ('\n') to see what line you are on. Copy chars from buffer_file_in to buffer_file_out up to that point. Now, write your new contents into buffer_file_out at that point. Then, finish copying the rest of buffer_file_in into buffer_file_out after your inserted chars.
Seek to the beginning of the file with fseek(file_pointer, 0, SEEK_SET);
Write the buffer_file_out buffer contents into the file with fwrite().
Close the file with fclose().
There are some optimizations you could do here, such as storing the index where you want to begin your insertion, and not copying the chars up to that point into buffer_file_in, but rather, simply copying the remaining of the file after that into buffer_file_in, and then seeking to that point later and writing only your new contents plus the rest of the file. This avoids unnecessarily rewriting the very beginning of the fie prior to the insertion point is all.
(Probably preferred) you could also just copy the file and the changes you insert straight into buffer_file_out in one shot, then write that back to the file starting at the beginning of the file. This would be very similar to #pm100's approach, except using 1 file + 1 buffer rather than 2 files.
Look for other optimizations and reductions of redundancy as applicable.
My approach above uses 1 file and 1 or 2 buffers in RAM, depending on implementation. #pm100's approach uses 2 files and 0 buffers in RAM (very similar to what my 1 file and 1 buffer approach would look like), depending on implementation. Both approaches are valid.
Say that I have a file with the below format
<records count="n">
record line 1
record line 2
.
.
.
record line n
</records>
I'll have to open this file and change the value of n to another value based on some logic. After change my file should look like.
<records count="m">
record line 1
record line 2
.
.
.
record line n
</records>
I can open the file in OPEN I-O mode and change the first line using the REWRITE option to replace the first line. But I don't want to use these methods. Is there a way to achieve the same logic using OPEN INPUT and OPEN OUTPUT mode and replace the line with WRITE method.
Is there a way to achieve the same logic using OPEN INPUT and OPEN
OUTPUT mode and replace the line with WRITE method[?]
No, that would leave you with only the <records count="m"> in the file. All other records would be lost!
As long as the length of the first record is the same, after changing n to m, REWRITE is the most straight forward way to update that record.
Perhaps, if you explain why you want to use WRITE, there may be something else that could be done.
If the file is not 'too' large, read all the records into memory, change the first record, then write all the records to the file.
If the file is 'too' large, copy the file changing the first record, delete the first file, then rename the copy.
Perhaps less efficient for 'too' large, sort the file by adding a sequence number and changing the first record. This simply uses the sort file to hold the data, temporarily. Possibly a poor choice for a program to be converted.
You need to define what the limit for 'too' is.
There are non-standard routines for file access in Micro Focus, but those might be more difficult to convert.
Here's my issue: I have a file with the highscore written in it (just the first line, no nicknames, just the highscore), I need to read that line and compare it with the actual score obtained in the game session, if the score is higher, overwrite the file with the new value, but if I try to read it I get a null value... Seems like i'm not reading it the right way. What's wrong with my code?
Thanks for the help!
local path = system.pathForFile( "data.sav", system.DocumentsDirectory )
local file = io.open( path, "w+" )
highscore_letta = file:read("*n")
print(highscore_letta)
if (_G.player_score > tonumber(highscore_letta)) then
file:write(_G.player_score)
end
io.close( file )
I had this problem myself. I found out that if you open a file in "w+" mode, the current contents are deleted, so that you can write new contents. So to read and write you have to open the file twice. First, you open the file in "rb" mode and get the file contents, then close it. Then you reopen it in "wb" mode, write the new number, and close it.
In Windows, you need "b" in the file mode. Otherwise, the strings that you are reading and writing may be modified in unexpected ways: for instance, a newline ("\n") may be replaced with carriage return–newline ("\r\n").
The file modes that Lua supports are borrowed from the C language. (I found a description on page 305 of what I guess is a draft of the C specification.) I think the Lua manual sort of assumes that you will know what these modes mean, as an experienced C programmer would, but to me it wasn't at all obvious.
Thus to read a number and then write a new one:
local filepath = "path/to/file"
-- Create a file handle that will allow you to read the current contents.
local read_file = io.open(filepath, "rb")
number = read_file:read "*n" -- Read one number. In Lua 5.3, use "n"; the asterisk is not needed.
read_file:close() -- Close the file handle.
local new_number = 0 -- Replace this with the number you actually want to write.
-- Create a file handle that allows you to write new contents to the file,
-- while deleting the current contents.
write_file = io.open(filepath, "wb")
write_file:write(new_number) -- Overwrite the entire contents of the file.
write_file:flush() -- Make sure the new contents are actually saved.
write_file:close() -- Close the file handle.
I created a script to do these operations automatically, as they're somewhat annoying to type every time.
The mode "r+" or "r+b" is supposed to allow you to read and write, but I couldn't get it to work when the original contents are longer than the new contents. If the original contents are "abcd", four bytes, and the new contents are "efg", three bytes, and you write at offset 0 in the file, the file will now have "efgd": the last byte of the original contents is not deleted.
I have opened a file using a and r+ but when I use fseek and ftell the file pointer is always 0.
My file looks like this:
1 -3
2 -8
And I want to add another line between the two but it is added in the end after the last line.
Someone in another forum said that when you open the file in append the pointer is always zero and you have to open it in r+ and if that doesn't work "you have to read the complete data and then insert the data in the variables and write it back." but I don't understand what they mean by that.
Can anyone help with inserting numbers in the middle of a file?
Thanks!
Would something like this work?
To transfer the data?
rewind(fp);
fscanf(fp,"%d",&ch);
fprintf(fp1,"%d",ch);
fseek(fp,1,0);
fscanf(fp,"%d",&ch);
fprintf(fp1,"%d",ch);
Like others already said, there's no easy way to insert data in the middle of a file. If you really want to do this, you can implement the following steps:
Create a second file
Copy all data before the place you want to insert to the second file
Insert the line you want to the second file
Copy the remaining data to the second file
Delete the original file
Rename the second file
Other approach is using binary files instead of text files. Although binary files are a bit harder to learn, once you understand how they work you'll see that working with them is much like working with arrays. To perform this task, for example, you'd not even need to use an auxiliary file.
There is no open mode that will allow you to "insert" data into a file at a random point. The only place you can add data without overwriting existing data is the end of the file (what you get opening with mode "a").
If you want to insert at a random position, you need to do it yourself.
One of the easier ways is to re-write the file completely (transfer the start of the old file to a new file, add your data to the new file, transfer the rest of the old file, and rename/overwrite at the end).
The hard way: you need to "shift" all the data from your insertion point to the end-of-file manually. That's not trivial to get right.
There isn't an easy way to insert data in the middle of the file. A file is basically an array of characters. To add a character in the middle, you need to copy everything following your insertion point down one location. With a file you need to read the data that follows and write it after your addition.
Generally, when you want to do something like this you create a new file. You copy the old file into it up to the point where you want to insert, then you write the data you want to insert, then you copy the rest of the old file. Finally, you rename the new file to the old file.
How can I go back to the very beginning of a csv file and add rows?
(I'm printing to a CSV file from C using fprintf(). At the end of printing thousands of rows (5 columns) of data, I would like to go back to the top of the file and insert some dynamic header data (based on how things went printing everything). )
Thank You.
Due to the way files are structured, this is more or less impossible. In order to accomplish what you want:
write csv data to file1
write header to file2
copy contents of file1 to file2
delete file1
Or you can hold the csv data in ram and write it to file after you're finished processing and know the header.
Another option is to set aside a certain number of bytes for the header, which will work much faster for large files at minimal space cost. Since the space is allocated in the file at the start of the write, there aren't any issues going back and filling it in. Reopen the file as random access ("r+"), which points to the top of the file by default, write header, and close.
The simplest way would be to simply store the entire contents of the file in memory until you are finished, write out the header, and then write out the rest of the file.
If memory is an issue and you can't safely store the entire file in memory, or just don't want to, then you could write out the bulk of the CSV data to a temporary file, then when you are finished, write the header out to the primary file, and copy the data from the temporary file to the primary file in a loop.
If you wanted to be fancy, after writing the main CSV data out to the primary file, you could loop through the file from the beginning, read into memory the data that you're about to overwrite with the header, then write the header over top of that data, and so forth, read each chunk into memory, overwrite it with the previous one until you reach the end and append the final chunk. In this way you "insert" data at the beginning, my moving the rest of the file down. I really wouldn't recommend this as it will mostly just add complexity without much benefit, unless there is a specific reason you can't do something simpler like using a temporary file.
I think that is not possible. Probably the easiest way would be to write the output to a temporary file, then create the data you need as the dynamic header, write them to the target file and append the previously created temporary file.
write enough blank spaces in the first line
write data
seek(0)
write header - last column will be padded with spaces