Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 8 years ago.
Improve this question
I have a homework assignment and we must use .txt files.
Here's my file example:
1 John 1234 558
2 Myke 2222 9876
...
I want to overwrite the 558 number in the file. The ID (1,2...) are given. I've been searching around and the fopen() function only provides arguments for beginning and appending.
You can use the fopen("filename", "r+b") to open a file for updating (in binary mode).
You can then use fseek to set were you want to write next and use fwrite/fputs or similar to update the data.
For example, say you start with a file test.text which looks like this
0123456789abcde
0123456789abcde
0123456789abcde
you can use the following program
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *f;
if(!(f = fopen("./test.text", "r+b"))) //open the file for updating
return -1;
fseek(f, 16, SEEK_SET);//set the stream pointer 16 bytes from the start.
const char message[] = "Hello, World!";
fputs(message,f);
return 0;
}
and the result would be
0123456789abcde
Hello, World!de
0123456789abcde
you will still need to first search the file for the id you want to replace, and you may run into problems when you want to replace "558" with "12345" unless there are extra spaces on the line to pad the output. As you will start overwriting data from the next line.
fopen to open the file, then seek to the right bit, then write the appropriate bits, taking great care not to overwrite anything further in the file you didn't want to overwrite!
If you need to insert more data than was taken up by the existing text then you'll have to re-append the rest of the file contents from that point.
It is usually easier to re-write the file in its entirety. You must have a reading and a writing function already. So you read, the modify your in-memory data structures, then you write everything out again.
There are functions to seek to a given position in a file, but this position is a byte offset in the file. You do not know the offset in advance, so you will need to read the file line per line until you discover the line with the given ID. Then you can skip the name, the first number and you are at the 558. The problem now is that you can overwrite the 558 in the file, but you cannot write 12 and delete the 8 from 558. You also cannot replace the 558 with a 1234 because you would overwrite the 558 with 123 and would need to insert the 4.
One simple solution would be to work with a second file. You could read file 1 line per line and copy each line to file 2. Despite the line with the given ID. You would modify that line before writing it to file 2.
If you know how to do it, you could also work with a big buffer and do the replacement in file 1 without the need for a second file.
If you are allowed to work with two files, you should do that. If the files are short and you are allowed to read the complete file into memory, you could read the file, do the modification in memory and write back the file.
(Assuming your .txt file consists of the above mentioned 4 fields) You can have two FILE pointers one with read permissions and the other with write permission. Suppose your file is named xyz.txt, let fp_read with read access point to it, where let fp_write point to a new file xyz_bkp.txt.
Variables:
char *curr_line, *name;
int id, second_num, third_num;
The trick here is to read the file xyz.txt line by line into a string(say curr_line)
Then read the values in the line into different variables using sscanf. Eg-
sscanf(curr_line, "%d %s %d %d", &id, name, &second_num, &third_num);
Now based on values of the variables, either write the values to the xyz_bkp.txt file unconditionally or change them as per your will.
NOTE: After you are done, you would need to delete the original xyz.txt and rename xyz_bkp.txt to xyz.txt(simple enough)
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.
This question already has answers here:
How to fgets() a specific line from a file in C?
(5 answers)
Closed 7 years ago.
I want to read a specific line from a text file without reading the whole file line by line. For Example, if I have 10 lines in a text file and I have to read 6th line, I will not read the first 5 lines but will directly read the 6th one. Can anyone help me??
This question is answered here
Quoting from above,
Unless you know something more about the file, you can't access specific lines at random. New lines are delimited by the presence of line end characters and they can, in general, occur anywhere. Text files do not come with a map or index that would allow you to skip to the nth line.
If you knew that, say, every line in the file was the same length, then you could use random access to jump to a particular line. Without extra knowledge of this sort you simply have no choice but to iterate through the entire file until you reach your desired line.
Credits : Quoted answered was by David Heffernan
You could 'index' the file. Please note that this is only worth the effort if your text file:
is big
is frequently read and rarely written
The easiest (and probably most efficient) way is to use a database engine. Just store your file in a table, one row for each line.
Alternatively, you could make your own indexing mechanism. Basically, this means:
create a new file (the index)
scan the entire text file once, storing the offset of each line in the index file
repeat the above each time the text file changes
Finding line n in the text file requires two seeks:
read the nth offset from the index
read a line from the text file, starting at the offset found in the index
I need to rewrite a char on a file, or delete some lines. Is there a way to achieve this without rewriting the whole file?
Example: I need to change the char "8" at line 10 with char "4".
pollo
ciao fred
98/98/34 42ddw
4
10
1234567890
cristo
ciao liby
98/98/34 fre42ddw
8
20
12345678901234567890
Look at
int fseek (stream, offset, origin);
You can move to a specific offset and write a symbol there. But to find an offset of char to replace you still need to read all symbols before it.
In a nutshell, yes, you can modify data at arbitrary positions in the file using random-access API methods. Of course, how the OS and filesystem handle this behind the scenes may result in the entire file being rewritten anyways.
You can use fseek and fputc, if you know exactly the position of the char. If not, you should better first fread the file and find the needed position. For other utility functions, see <stdio.h>.
Note that <stdio.h> is byte-based, rather than line-based. With line-based methods you would basically need to rewrite the file.
For deleting line from the file, well, you can just transfer all the characters from the positions i + [end of the line to be deleted] + 1 to positions i + [start of the line to be deleted]. Or read the whole into a buffer and manipulate the characters there. But for such a task, line-based functions are more appropriate.
I need to add a string before the 45th byte in an existing file. I tried using fseek as shown below.
int main()
{
FILE *fp;
char str[] = "test";
fp = fopen(FILEPATH,"a");
fseek(fp,-45, SEEK_END);
fprintf(fp,"%s",str);
fclose(fp);
return(0);
}
I expected that this code will add "test" before the 45th char from EOF, instead, it just appends "test" to the EOF.
Please help me to find the solution.
This is continuation of my previous question
Append item to a file before last line in c
Open it with mode r+ (if it already exists) or a+ (if it doesn't exist and you want to create it). Since you're seeking to 45 bytes before the end of file, I'm assuming it already exists.
fp = fopen(FILEPATH,"r+");
The rest of your code is fine. Also note that this will not insert the text, but will overwrite whatever is currently at that position in the file.
ie, if your file looks like this:
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
Then after running this code, it will look like this:
xxxxxxxtestxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
If you really want to insert and not overwrite, then you need to read all the text from SEEK_END-45 to EOF into memory, write test and then write the text back
Don't open it as append (a) if you plan to write at arbitrary positions; it will force all writes to the end of the file. You can use r+ to read or write anywhere.
To avoid platform-specific configurations, always explicitely indicate the binary or text mode in your fopen() call.
This will save you hours of desperations if you port your code one day.
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.