Inserting text into a txt file - c

I'm trying to accomplish the following:
I have a text file with the last printable character "]" in a separate line.
This line is not necessary to be the last line of the file. Some blank lines (line returns) can be there.
The purpose of the project is to insert new text before the line with "]".
The way I try to implement this is to search the file from the end of the file to find the line number with the character "]" (char_line).
Copy line by line from the original file rules1.txt to rules2.txt up to the line char_line. Next step is to append the new text with "]" at the end.
After that, I can delete the original file and rename the new file from rules2.txt to rules1.txt.
The problem I have is that the program finds the line with the character "]" and I can do a printf and see the correct line number.
I am assigning char_line = "%d".
When I'm using if(i < char_line) the file is copied all the way to EOF.
If I assign a numerical value, char_line = 23, the file is copied up to line 22, which is what I want.
This is the part of the code which should find line number for "]", copy line by line rules1.txt to rules2.txt up the line with "]".
#include <stdio.h>
int main(void) {
int end, loop, line;
char str[64];
FILE *file;
FILE *write;
int char_line;
int ret;
file = fopen("rules1.txt", "r");
if (file == NULL) {
printf("Failed to open file\n");
return -1;
}
int ch, line_num = 0;
do {
ch = fgetc(file);
if(ch == '\n')
line_num++;
} while (ch != EOF);
// last line doesn't end with a new line!
// but there has to be a line at least before the last line
if(ch != '\n' && line_num != 0)
line_num++;
fclose(file);
line = line_num-1;
start:
file = fopen("rules1.txt", "r");
if (file == NULL) {
printf("Failed to open file\n");
return -1;
}
for(end = loop = 0;loop<line;++loop){
if(0==fgets(str, sizeof(str), file)){//include '\n'
end = 1;//can't input (EOF)
break;
}
}
if(!end)
if (strncmp ("]", str, 1) == 0){
char_line ="%d";
goto next;
} else if(line >1){
line == line--;//WTF?
fclose(file);
goto start;
} else //What to do here?
next:
file = fopen("rules1.txt", "r");
write = fopen("rules2.txt", "w");
char linec [64]; /* line size */
int i = 0;
while (fgets(linec, sizeof(linec), file)) { /* read line from file */
i++;
if(i < char_line) {
fprintf (write , linec); /* write line to file */
}
}
fclose(file);
fclose(write);
return(0);
}

You have declared int char_line; and later you code
char_line ="%d";
This is nonsense. Since a literal string is some char[] array (better think of it as some constant array), decayed to a pointer, and assigning a pointer to an int does not make sense at all. On many machines (x86-64 notably), a pointer has 64 bits but an int has only 32 bits.
Please, compile your code with all warnings and debug info, so gcc -Wall -Wextra -g with GCC, improve your code to get no warnings, then use the debugger gdb.
Take several days to read some good books on C programming. Be aware and work hard to avoid undefined behavior. Use the debugger to run your program step by step and query its state to understand what is happening.
Read the documentation of every standard function you are using such as fgets.
You probably want a loop that reads every line, and copies sometimes that line to another file.

Related

Reading a text file line by line in c

I try to read the file that I wrote the first three line, line by line. However, it enters infinity loop. How can I stop it at the end of the file?
while(fscanf(infile, "%[^\n]", ch) != EOF)
printf("%s", ch);
Tiffany;Evans Smith;F;22/01/1989;
Alex;Williams;M;23/06/1988;
Clay;Bristol;F;30/12/1989;
There are multiple ways of reading a text file line by line. Hopefully, the following code answers your question.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *infile;
char data[BUFSIZ];
infile=fopen("filename","r");
while((fgets(data,BUFSIZ,infile)!=NULL))
puts(data);
}
if you want to use fscanf, you can use this code :
int ret;
while(ret = fscanf(infile,"%s",str))
{
if (ret == EOF)
break;
if(ret >0 )
{
cout << str <<endl;
}
else
{
break;
}
}
here, int ret is:
EOF, if the pointer is reached end of file.
0, if no input matched with the variable
>0, number of matched variables with the file input

C - fgets skips CR character

I have a c code, simply reads a line from a txt file. The file has only one line which is as below:
The code snippet to read this line is:
int** readFile(char* filename){
int col=0, row =0;
int i=0;
int* numList[2048];
for(int i = 0; i<2048; i++)
numList[i] = (int*) malloc(6*sizeof(int));
if(NULL == numList){
printf("Memory error!");
}
char * token = NULL;
char currentLine[25] = {'\0'};
FILE* file = fopen(filename, "r");
if(NULL != file){
printf("File is opened successfully\n");
if( NULL != fgets (currentLine, 60, file) )
{
int i = 0;
while (NULL != currentLine[i]){
printf("%d ", currentLine[i]);
i++;
}
}
}
else
{
printf("File I/O Error");
return NULL;
}
fclose(file);
return numList;
}
When this code runs, I get the following output:
I observed something suspicious, which is, as you can see in the first screenshot (Content of txt file), Notepad++ shows CR LF at the end of the line. But in the output, I see 10 as the last character which is LF.
Probably I am missing a very primitive point but, I couldn't understand why CR character is not there.
Needless to say, platform is windows and this is a console program.
Thanks&Regards.
You're opening the file in text mode. This mode ensures you can handle text files the same on any platform.
C specifies '\n' as the end of line. In Windows, the end of line is the sequence "\r\n". C (in this case, the standard library implementing stdio) will automatically translate this for you. Reading from a file on Windows in text mode will give you just \n for \r\n.
If you want to see exactly the byte contents of the file, you have to open it in binary mode instead:
FILE* file = fopen(filename, "rb");

Why is the number of lines showing as 0 when I also print the lines out but works fine when its just the line count

So both the code to print the lines from the txt file and the code to count the lines in the txt file work fine when the other is commented out but when i try to have both work only the code that comes first works e.g. if i put the code to print out the lines first, the line count is always zero. However if i put the code to count the lines first, the number is correct but the lines from the txt file are not printed :S
#include <stdio.h>
int main(int argc, char const *argv[])
{
const int SIZE = 128;
char line[SIZE];
FILE *srcFile;
int c;
int count = 0; // Line counter (result)
if (argc == 1)
{
printf("No command line arguments given!\n");
return 1;
}
srcFile = fopen(argv[1], "r");
if (srcFile == NULL)
{
perror("\n*** FILE OPEN FAILED ***");
}
else
{
printf("\n*** FILE OPEN SUCCESSFUL ***\n\n");
}
while(fgets(line, SIZE, srcFile) != NULL)
{
printf("%s", line);
}
for (c = fgetc(srcFile); c != EOF; c = fgetc(srcFile))
{
if (c == '\n')
{
count ++;
}
}
if(c != '\n' && count != 0)
{
count ++;
}
printf("The file %s has %d lines\n ", argv[1], count);
fclose(srcFile);
return 0;
}
Here is a quick overview of how working with files is done in most programming languages:
When you open a file in a program you obtain a handle to that file. What the handle representation is depends on the language. In c it is the FILE structure. The handle contains - among other things - a file position indicator. Every read and write to that file through this handle happens at that position. Usually a read/write operation advances this file position indicator. Think about it: how do consecutive reads know to each read where the previous one left? You don't provide an argument to the read function telling it where to read from. You just "say" read. What happens is that each read call reads at the file position indicator and then advances this indicator, thus when the next read happens the handle has an updated file position indicator.
So the solution to your problem is - as mentioned in the comments - to put this position indicator to the beginning of the file. In c this can be done with rewind.
curious how the code fragment would have to look to include the line
count int the same loop as the print lines
Simple. Pseudocode:
line_count = 0
while (read line successful)
{
print line
increment line_count
}
print line_count

Using fgets to read and print multiple lines from .txt file

FILE *fp = fopen("story.txt", "r");
if(fp == NULL){
printf("\nError opening file.\nExiting program.\n");
exit(1);
}
char text[100];
while(fgets(text, 100, fp) != NULL){
printf("%s", text);
}
printf("\n");
fclose(fp);
I'm trying to print the first 100 characters of a text file, including new lines, however when I use the code above it presents some weird behavior. First of all, it only prints the very last line of the text file, which itself is under 100 characters. Also, if I include two print statements in the while loop i.e.
while(fgets(text, 100, fp) != NULL){
printf("%s", text);
printf("%s", text);
}
It prints a lot more than 125 chars of the text file (somewhere in the thousands, it's a big text file), and the contents of said text is a bunch of seemingly random segments from the file in one constant stream, no new lines or anything.
So I guess my question is is there any way to use fgets so that it prints the text in the file, starting from the top, and includes new lines? I eventually have to use this to turn a text file into a character array, so that I can make a new, modified character array based off of that array, which will be printed to a new text file. So if there is a better way to approach that end goal, that would be appreciated.
EDIT: after some discussion in the comments I've realized that the text I am using is just one big block of text with carriage returns and no newlines. I guess at this point my main problem is how to turn this text file with carriage returns into a character array.
If the goal is to read a text file in lines of 100 characters, and to do away with the carriage returns, you can still use fgets() as long as you remember that fgets() will take characters up to and including the next newline, or until one less than the specified number of characters has been read.
The code below reads a line of text, up to BUFFER_SZ-1 characters, increases the memory allocation to hold a new line of text, and copies the line into the allocated space, removing carriage returns and any trailing newlines. Note that the address of the reallocated space is first stored in a temporary pointer. realloc() returns a null pointer in the event of an allocation error, and this step avoids a potential memory leak.
Since the lines are broken at BUFFER_SZ-1 characters, words may be split across lines, and you may want to develop additional logic to handle this. It would be more efficient to reallocate in larger chunks and less frequently, rather than once for every line, as is done here. Also note that it may be useful to open the file in binary mode to more closely parse line endings.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SZ 100
int main(void)
{
FILE *fp = fopen("story.txt", "r");
if (fp == NULL) {
fprintf(stderr, "Unable to open file\n");
exit(EXIT_FAILURE);
}
char buffer[BUFFER_SZ];
char (*text)[sizeof buffer] = NULL;
char (*temp)[sizeof buffer] = NULL;
size_t numlines = 0;
while (fgets(buffer, sizeof buffer, fp) != NULL) {
++numlines;
/* Allocate space for next line */
temp = realloc(text, sizeof(*text) * numlines);
if (temp == NULL) {
fprintf(stderr, "Error in realloc()\n");
exit(EXIT_FAILURE);
}
text = temp;
/* Copy buffer to text, removing carriage returns and newlines */
char *c = buffer;
char *line = text[numlines-1];
while (*c != '\n' && *c != '\0') {
if (*c != '\r') {
*line++ = *c;
}
++c;
}
*c = '\0';
}
if (fclose(fp) != 0) {
fprintf(stderr, "Unable to close file\n");
}
for (size_t i = 0; i < numlines; i++) {
printf("%s\n", text[i]);
}
free(text);
return 0;
}
Another option would be to replace the carriage returns with newlines. This may be what OP had in mind. The above program is easily modified to accomplish this. Note that the \n is removed from the printf() statement that displays the results, since newlines are now included in the strings.
...
/* Copy buffer to text, converting carriage returns to newlines */
char *c = buffer;
char *line = text[numlines-1];
while (*c != '\n' && *c != '\0') {
if (*c == '\r') {
*line++ = '\n';
} else {
*line++ = *c;
}
++c;
}
*c = '\0';
}
if (fclose(fp) != 0) {
fprintf(stderr, "Unable to close file\n");
}
for (size_t i = 0; i < numlines; i++) {
printf("%s", text[i]);
}
...
It doesn't copy one line onto the end of another. It simply reuses the buffer you keep passing it. If you want multiple lines stored, copy them to another buffer, and concatenate them. (See: strcat)

reading just one line from file in c code

My program reads the specific line from the file properly, however it reads the whole file form the line I specify onward. I am trying to print just one line at a time. How can I make it just read the one line?
The code:
int main()
{
int lineNumber = 5;
static const char filename[] = "Text.txt";
FILE *file = fopen(filename, "r");
int count = 0;
if ( file != NULL )
{
char line[256]; /* or other suitable maximum line size */
while (fgets(line, sizeof line, file) != NULL) /* read a line */
{
if (count == lineNumber)
{
printf("%s", line);
//in case of a return first close the file with "fclose(file);"
}
else
{
count++;
}
}
fclose(file);
}
}
After you've found the desired line, just use a break to exit the loop:
if (count == lineNumber)
{
printf("%s", line);
break;
}
if (count == lineNumber)
{
printf("%s", line);
//in case of a return first close the file with "fclose(file);"
count++;
}
increment count when you get the line you specify,otherwise count will not proceed to indicate next line. That is why your code printed all lines once you got the line you specified. Because the line number count wont increase once it becomes equal to linenumber. so add count++.
You can even break the loop since you don't require rest of the lines to be read after you get the specified line.

Resources