Read From file c - c

I'm working on a project of booking , so the idea of project when the program starts it should read a data from a file called databook and save them on the struct , and everytime i'm adding a book it should add to program
the difficult i found the name has a space between name and nickname so i used scanf but the problem is scanf don't read full line i used scanf("%[^\n]s",) but it doesnt work
the source code below to understund more
#include <stdio.h>
#include <stdlib.h>
#define MAX_ARRAY_SIZE 5
typedef struct Book
{
char BookName[50];
int BookISBN;
int Borrowed;
char BorrowerName[50];
char Field[50];
}Book;
Book book[MAX_ARRAY_SIZE];
void ReadFile(char* fileName);
int main(int argc, char* argv[])
{
char* fileName = "c1.txt";
ReadFile(fileName);
int i = 0;
for (i = 0; i < MAX_ARRAY_SIZE; i++)
{
printf("Book Name is : %s\n", book[i].BookName);
printf("Book ISBN is : %d\n", book[i].BookISBN);
printf("Borrowed is : %d\n", book[i].Borrowed);
printf("Borrower Name is : %s\n", book[i].BorrowerName);
printf("Field is : %s\n", book[i].Field);
printf("\n");
}
exit(EXIT_SUCCESS);
}
void ReadFile(char* fileName)
{
FILE* filePtr = NULL;
int i = 0;
if ((filePtr = fopen(fileName, "r")) == NULL)
{
printf("Error : Unable to open %s for reading\n");
exit(EXIT_FAILURE);
}
while (fscanf(filePtr, "%s%d%d%s%s", &book[i].BookName, &book[i].BookISBN, &book[i].Borrowed,&book[i].BorrowerName,&book[i].Field) != EOF)
{
i++;
}
fclose(filePtr);
}
for databook
Technique Informatique //BookName1
90023 //BookISBN1
1 //(OR O) - means 'Borrowed OR not
Adam Ridge //BorrowerName1 (None in case Not borrowed)
special//(field)
Data Structures //BookName1
23451 //BookISBN1
0 //(OR O) - means 'Borrowed OR not
None //BorrowerName1 (None in case Not borrowed)
Computer Science //(field)
E-commerce Blockchain //BookName1
14678 //BookISBN1
1 //(OR O) - means 'Borrowed OR not
Adam Ridge //BorrowerName1 (None in case Not borrowed)
Business //(field)

Well you should be using fgets for reading string, as other people have already said.
Nevertheless, and to answer you question, here is some advice that might help you:
Book structure contains char arrays (char []) not pointers (char *), so reading into those variables does nor have the & symbol, e.g.:
fscanf(filePtr, "%[^\n]%d\n%d\n%[^\n]%*c%[^\n]%*c", book[i].BookName...) != EOF)
The correct format of the fscanf function for this case is:
fscanf(filePtr, "%[^\n]%d\n%d\n%[^\n]%*c%[^\n]%*c", book[i].BookName, &book[i].BookISBN, &book[i].Borrowed, book[i].BorrowerName, book[i].Field) != EOF)
Where:
a) %[^\n] -> reads a full line
b) %d\n -> reads an int and an end of line
c) [^\n]%*c -> reads a full line and any extra chars. Note, that if you use * in the format string, it suppresses assignment:
%*c = read 1 character, but don't assign it to any variable

As already pointed out by people in comments, you should try to use fgets() for reading file and then sscanf for reading integers from the string. Here is an example:
int ReadFile(char* fileName) {
FILE* filePtr = NULL;
int i = 0;
if ((filePtr = fopen(fileName, "r")) == NULL) {
printf("Error : Unable to open %s for reading\n");
exit(EXIT_FAILURE);
}
char input[100];
char *result;
while ((result = fgets(input, 100, filePtr)) != NULL) {
// Book Name
input[strlen(input) - 1] = '\0'; // Trim trailing \n
strcpy(book[i].BookName, input);
// Book ISBN
result = fgets(input, 100, filePtr);
if (result == NULL) break;
sscanf(input, "%d", &book[i].BookISBN);
// Book Borrowed
result = fgets(input, 100, filePtr);
if (result == NULL) break;
sscanf(input, "%d", &book[i].Borrowed);
// Book Borrower Name
result = fgets(input, 100, filePtr);
input[strlen(input) - 1] = '\0'; // Trim trailing \n
if (result == NULL) break;
strcpy(book[i].BorrowerName, input);
// Book Field
result = fgets(input, 100, filePtr);
input[strlen(input) - 1] = '\0'; // Trim trailing \n
if (result == NULL) break;
strcpy(book[i].Field, input);
i++;
}
fclose(filePtr);
return i;
}
When I run this code on your file, I'm able to see documents being printed:
c-posts : $ gcc booking.c
c-posts : $ ./a.out
Book Name is : Technique Informatique
Book ISBN is : 90023
Borrowed is : 1
Borrower Name is : Adam Ridge
Field is : special
Book Name is : Data Structures
Book ISBN is : 23451
Borrowed is : 0
Borrower Name is : None
Field is : Computer Science
Book Name is : E-commerce Blockchain
Book ISBN is : 14678
Borrowed is : 1
Borrower Name is : Adam Ridge
Field is : Business

Related

How do i search for specific data in txt file from just ID

So i was able to display the txt file but when i search with a specific vaccine code it display the first line in the txt file. How do i get the specific vaccine from the txt file just from searching its vaccine code ?
this is the data in my vaccine.txt:
Pfizer |PF |USA |2 |50
Sinovac |SV |China |2 |18.8000
AstraZeneca |AZ |UK |2 |10.0000
Sputnik V |SP |Russia |2 |10.0000
CanSinoBio |CS |China |1 |10.9000
This is my code
void searchvac() {
char code[32];
int i = 0, option;
FILE* fptr;
printf("\n---------------------------------------------------------------------");
printf("\n\t\t\t Search Vaccine availability");
printf("\n---------------------------------------------------------------------");
printf("\nEnter Vaccine Code: ");
scanf("%c", code);
getchar();
fptr = fopen("Vaccine.txt", "r");
if (!fptr) { perror("Vaccine.txt"); return; }
char line[200];
while (fgets(line, sizeof line, fptr))
if (strstr(line, code)) {
printf("\n======================================================================\n");
printf("Vaccine Name\t Code\t Produce By\tDosage\t Population Recovered\n");
printf("======================================================================\n");
printf("%s", line);
break;
}
printf("\nDo you want to search another Vaccine? (Press 1 to continue & any NUMBER to go back) ");
scanf("%d", &option);
fclose(fptr);
switch (option) {
case 1:
searchvac();
break;
default:
menu();
break;
}
printf("\n");
menu();
when i input the dosage (which is 2). it will also print all vaccine with 2 dosage. what i want is the user only allowed to input the vaccine code only.
What is wrong from my code can anyone help ?
The line
scanf("%c", code);
will not work, as the %c format specifier will only read a single character. However, your code consists of two characters. Therefore, you may want to change it to the following:
scanf("%31s", code);
This will read a whole word of input, up to 31 characters (more won't fit into the buffer).
However, for line-based input, you may want to consider using fgets instead of scanf, as using scanf has several disadvantages. See this link for further information:
A beginners' guide away from scanf()
Another problem is that the line
if (strcmp(line, code)) {
won't work, because if the user enters for example "PF"
then strcmp will compare that string with
"Pfizer |PF |USA |2 |50\n"
and determine that they are not identical. Therefore, you must first extract the code PF from the string from the input file, and only afterwards compare that string to the user input.
EDIT: Meanwhile, you have edited your question to use strstr instead of strcmp. I don't recommend using that function, because that function may give false positives. For example, if there happens to be a character sequence in another field which matches the code the user entered, then strstr will report a match, even if the code in that line is different.
A common way extract individual fields delimitered by a specific character is to use the function strtok. However, that function modifies the string by inserting null terminating characters inside it. Since we may want to print out that string later, we do not want to do that. Therefore, I recommend to use strchr and sscanf instead, like this:
while ( fgets(line, sizeof line, fptr) != NULL )
{
char line_code[3];
char *p;
//find end of first field
p = strchr( line, '|' );
if ( p == NULL )
continue;
//make p point to start of next field
p++;
//extract code
if ( sscanf( p, "%2s", line_code ) != 1 )
continue;
//compare user-entered code with code from current line
if ( strcmp( user_code, line_code ) != 0 )
continue;
printf("\n======================================================================\n");
printf("Vaccine Name\t Code\t Produce By\tDosage\t Population Recovered\n");
printf("======================================================================\n");
printf("%s", line);
break;
}
}
Note that for the code above to work, you will have to rename code to user_code in your program. It does not make sense to have a variable named code in your program if your program handles two codes, one user-entered code and one code from the current line of the input file. In order to distinguish these two codes, I use the variable names user_code and line_code in my program.
If you want to compare only a portion of the line, you cannot use strcmp to compare the whole line. But don't do a linear search through the file! Build a search tree. If you want to have a balanced search tree, the code can get fairly complicated, but if you're willing to accept a linear search for the worst case (which may happen if you never rebalance the tree) it can be done fairly easily. eg:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct vac {
char name[50];
char code[3];
char producer[20];
int dosage;
float recovered;
struct vac *child[2];
};
FILE * xfopen(const char *path, const char *mode);
void * xmalloc(size_t s);
static struct vac *
push(struct vac *h, const struct vac *v)
{
if( h ){
int c = strcmp(h->code, v->code);
if( c == 0 ){
fprintf(stderr, "Duplicate entry ignored\n");
} else {
h->child[ c > 0 ] = push(h->child[ c > 0 ], v);
}
} else {
h = xmalloc(sizeof *h);
memcpy(h, v, sizeof *h);
}
return h;
}
static int
seek(const struct vac *h, const char *code)
{
if( h ){
int c = strcmp(h->code, code);
if( c == 0 ){
printf("%s\n", h->name);
return 1;
} else {
return seek(h->child[ c > 0 ], code);
}
}
return 0;
}
int
main(int argc, char *argv[])
{
char buf[128];
struct vac t = {0}, *h = NULL;
FILE *ifp = argc > 1 ? xfopen(argv[1], "r") : stdin;
while( 5 == fscanf(ifp, " %49[^|] | %3s | %19s | %d | %f",
t.name, t.code, t.producer, &t.dosage, &t.recovered) )
{
h = push(h, &t);
}
printf("Enter code to search for: ");
fflush(stdout);
while( scanf("%127s", buf) == 1 ){
if( ! seek(h, buf) ){
fprintf(stderr, "Not found\n");
}
}
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}

Two words in a string from text file

I'm trying to get two words in a string and I don't know how I can do it. I tried but if in a text file I have 'name Penny Marie' it gives me :name Penny. How can I get Penny Marie in s1? Thank you
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello world!\n");
char s[50];
char s1[20];
FILE* fp = fopen("file.txt", "rt");
if (fp == NULL)
return 0;
fscanf(fp,"%s %s",s,s1);
{
printf("%s\n",s);
printf("%s",s1);
}
fclose(fp);
return 0;
}
Change the fscanf format, just tell it to not stop reading until new line:
fscanf(fp,"%s %[^\n]s",s,s1);
You shall use fgets.
Or you can try to do this :
fscanf(fp,"%s %s %s", s0, s, s1);
{
printf("%s\n",s);
printf("%s",s1);
}
and declare s0 as a void*
The other answers address adjustments to your fscanf call specific to your stated need. (Although fscanf() is not generally the best way to do what you are asking.) Your question is specific about getting 2 words, Penny & Marie, from a line in a file that contains: name Penny Marie. And as asked in comments, what if the file contains more than 1 line that needs to be parsed, or the name strings contain a variable number of names. Generally, the following functions and techniques are more suitable and are more commonly used to read content from a file and parse its content into strings:
fopen() and its arguments.
fgets()
strtok() (or strtok_r())
How to determine count of lines in a file (useful for creating an array of strings)
How to read lines of file into array of strings.
Deploying these techniques and functions can be adapted in many ways to parse content from files. To illustrate, a small example using these techniques is implemented below that will handle your stated needs, including multiple lines per file and variable numbers of names in each line.
Given File: names.txt in local directory:
name Penny Marie
name Jerry Smith
name Anthony James
name William Begoin
name Billy Jay Smith
name Jill Garner
name Cyndi Elm
name Bill Jones
name Ella Fitz Bella Jay
name Jerry
The following reads a file to characterize its contents in terms of number of lines, and longest line, creates an array of strings then populates each string in the array with names in the file, regardless the number of parts of the name.
int main(void)
{
// get count of lines in file:
int longest=0, i;
int count = count_of_lines(".\\names.txt", &longest);
// create array of strings with information from above
char names[count][longest+2]; // +2 - newline and NULL
char temp[longest+2];
char *tok;
FILE *fp = fopen(".\\names.txt", "r");
if(fp)
{
for(i=0;i<count;i++)
{
if(fgets(temp, longest+2, fp))// read next line
{
tok = strtok(temp, " \n"); // throw away "name" and space
if(tok)
{
tok = strtok(NULL, " \n");//capture first name of line.
if(tok)
{
strcpy(names[i], tok); // write first name element to string.
tok = strtok(NULL, " \n");
while(tok) // continue until all name elements in line are read
{ //concatenate remaining name elements
strcat(names[i], " ");// add space between name elements
strcat(names[i], tok);// next name element
tok = strtok(NULL, " \n");
}
}
}
}
}
}
return 0;
}
// returns count, and passes back longest
int count_of_lines(char *filename, int *longest)
{
int count = 0;
int len=0, lenKeep=0;
int c;
FILE *fp = fopen(filename, "r");
if(fp)
{
c = getc(fp);
while(c != EOF)
{
if(c != '\n')
{
len++;
}
else
{
lenKeep = (len < lenKeep) ? lenKeep : len;
len = 0;
count++;
}
c = getc(fp);
}
fclose(fp);
*longest = lenKeep;
}
return count;
}
Change your fscanf line to fscanf(fp, "%s %s %s", s, s1, s2).
Then you can printf your s1 and s2 variables to get "Penny" and "Marie".
Try the function fgets
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
if( fgets (str, 60, fp)!=NULL ) {
/* writing content to stdout */
puts(str);
}
fclose(fp);
In the above piece of code it will write out the content with the maximum of 60 characters. You can make that part dynamic with str(len) if I'm not mistaken.

how to read specific lines of a text document and write them to another text | C

I have created a function that takes as a parameter the name of a source file, the name of a destination file and the beginning and end lines of the source file lines that will be copied to the destination file, like the example below. All I want to do is to input the lines that I want to copy to the other text file like the example below:
The code I show you just "reads" the content of the one text file and "writes" another one. I want to "write" specific lines that the user gives, not the whole text file
Inputs by the user:
Source_file.txt //the file that the destination file will read from
destination_file.txt //the new file that the program has written
2 3 // the lines that it will print to the destination file: 2-3
Source_file.txt:
1
2
3
4
5
6
destination_file.txt
2
3
code:
#include <stdio.h>
#include <stdlib.h>
void cp(char source_file[], char destination_file[], int lines_copy) {
char ch;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("File name not found, make sure the source file exists and is ending at .txt\n");
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF)
fputc(ch, destination);
printf("Copied lines %d from %s to %s \n",
lines_copy, source_file, destination_file, ".txt");
fclose(source);
fclose(destination);
}
int main() {
char s[20];
char d[20];
int lines;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the number of lines you want to copy\n\n");
printf(">subcopy.o ");
gets(s);
printf("destination file-> ");
gets(d);
printf("Lines: ");
scanf("%d", &lines);
cp(s, d, lines);
return 0;
}
In cp(), in order to select the lines to keep, you have to know their position in the input-file. Thus, you need to count lines.
Using fgets instead of fgetc will allow you to count the lines.
On the other hand, if I wanted to select lines 3 and 7 to 12 in a file, I'd use:
sed -n -e "3p;7,12p" < input.txt > output.txt
this is a very simple solution, let's say you know that the maximun length of a line will be 100 characters for simplicity (if a line is longer than 100 characters only the first 100 will be taken)
at the top (outside main) you can write
#ifndef MAX_LINE_SIZE
#define MAX_LINE_SIZE 100
#endif
i know many people don't like this but i think in this case it makes the code more elegant and easier to change if you need to modify the maximum line size.
to print only the wanted lines you can do something like this
char line[MAX_LINE_SIZE];
int count = 0;
while (fgets(line, MAX_LINE_SIZE, source)){
count++;
if (3 <= count && count <= 5){
fputs(line, destination);
}
}
The while loop will end when EOF is reched because fgets returns NULL.
P.S. there could be some slight errors here and there since i wrote it pretty fast and going by memory but in general it should work.
There are some problems in your program:
Do not use gets(), it may cause buffer overflows.
Always use type int to store the return value of fgetc() in order to distinguish EOF from regular byte values.
You pass an extra argument ".txt" to printf(). It will be ignored but should be removed nonetheless.
To copy a range of lines from source to destination, you can just modify your function this way:
#include <stdio.h>
#include <string.h>
#include <errno.h>
void cp(char source_file[], char destination_file[], int start_line, int end_line) {
int ch;
int line = 1, lines_copied;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("Cannot open input file %s: %s\n",
source_file, strerror(errno));
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
printf("Cannot open output file %s: %s\n",
destination_file, strerror(errno));
fclose(source);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF) {
if (line >= start_line && line <= end_line) {
fputc(ch, destination);
}
if (ch == '\n') {
line++;
}
}
lines_copied = 0;
if (line > start_line) {
if (line >= end_line) {
lines_copied = end_line - start_line + 1;
} else {
lines_copied = line - start_line + 1;
}
}
printf("Copied lines %d from %s to %s\n",
lines_copy, source_file, destination_file);
fclose(source);
fclose(destination);
}
int main() {
char source_file[80];
char destination_file[80];
int start_line, end_line;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the start and end line\n\n");
printf(">subcopy.o ");
if (scanf("%79s", source_file) != 1) {
return 1;
}
printf("destination file-> ");
if (scanf("%79s", destination_file) != 1) {
return 1;
}
printf("Start and end lines: ");
if (scanf("%d %d", &start_line, &end_line) != 2) {
return 1;
}
cp(source_file, destination_file, start_line, end_line);
return 0;
}

Get one string with space first and get another after tabs

I want to get strings from a .txt file, reading lines that each has name and phone number. and two \t characters are between names and phone numbers.
Example:
name\t\t\tphone#
thomas jefferson\t\t054-892-5882
bill clinton\t\t054-518-6974
The code is like this;
FILE *f;
errno_t err;
treeNode *tree = NULL, temp;
char input, fileName[100];
//get file name
while (1){
printf("Enter input file name: ");
scanf_s("%s", fileName, 100);
//f = fopen(fileName, "r");
if(err = fopen_s(&f, fileName, "r"))
printf("Cannot find file!\n");
//if (f == NULL)
// printf("Cannot find file!\n");
else
break;
}
//save info into BST
fscanf_s(f, " NAME Phone #\n", 20);
while (fscanf_s(f, "%[^\t]s\t\t%[^\n]s",
temp.name, temp.phoneNo, 50, 30) != EOF)
bstInsert(tree, temp.name, temp.phoneNo);
fclose(f);
treeNode is a binary search tree struct, and bstInsert is a function to add a struct containing 2nd and 3rd parameters to a binary search tree.
after I get the name of the file with scanf_s, code stops at the fscanf_s statement, showing below on the debugger;
temp.name: invalid characters in string.
temp.phoneNo: ""
I don't know how [^\t] or [^\n] works exactly. Can anyone let me know how I can deal with this problem? Thanks in advance!
"Can anyone let me know how can I deal with this problem?" I am no fan of scanf and family, so I deal with the problem by using different methods. Following your lead of using fopen_s and scanf_s I have used the "safer" version of strtok which is strtok_s.
#include <stdio.h>
#include <string.h>
int main (void) {
FILE *f;
errno_t err;
char *pName, *pPhone;
char input[100], fileName[100];
char *next_token = NULL;
// get file name
do{
printf("Enter input file name: ");
scanf_s("%s", fileName, 100);
if(err = fopen_s(&f, fileName, "r"))
printf("Cannot find file!\n");
} while (err);
// read and process each line of the file
while(NULL != fgets(input, 100, f)) { // has trailing newline
// isolate name
pName = strtok_s(input, "\t\r\n", &next_token); // strip newline too
if (pName == NULL) // garbage trap
pName = "(Error)";
printf ("%-30s", pName);
// isolate phone number
pPhone = strtok_s(NULL, "\t\r\n", &next_token); // arg is NULL after initial call
if (pPhone == NULL)
pPhone = "(Error)";
printf ("%s", pPhone);
printf ("\n");
}
fclose(f);
return 0;
}
Program output using a file with your example data:
Enter input file name: test.txt
name phone#
thomas jefferson 054-892-5882
bill clinton 054-518-6974

C programming Reading a specific line of a text file

So i've been given an exercise to work on: Have the user input a number and the program will display the line of text associated with that line for example
Password
abcdefg
Star_wars
jedi
Weapon
Planet
long
nail
car
fast
cover
machine
My_little
Alone
Love
Ghast
Input 3: Output: Star_wars
Now i have been given a program to solve this, however it uses the function getline() , which doesn't complie on DEV C++.
#include <stdio.h>
int main(void)
{
int end = 1, bytes = 512, loop = 0, line = 0;
char *str = NULL;
FILE *fd = fopen("Student passwords.txt", "r");
if (fd == NULL) {
printf("Failed to open file\n");
return -1;
}
printf("Enter the line number to read : ");
scanf("%d", &line);
do {
getline(&str, &bytes, fd);
loop++;
if (loop == line)
end = 0;
}while(end);
printf("\nLine-%d: %s\n", line, str);
fclose(fd);
}
All i need is to know how to do this, in a simple program without the use of getline()
Thanks
Edit: I also don't want to download software to make this work
use fgets instead of getline.
#include <stdio.h>
int main(void){
int end, loop, line;
char str[512];
FILE *fd = fopen("data.txt", "r");
if (fd == NULL) {
printf("Failed to open file\n");
return -1;
}
printf("Enter the line number to read : ");
scanf("%d", &line);
for(end = loop = 0;loop<line;++loop){
if(0==fgets(str, sizeof(str), fd)){//include '\n'
end = 1;//can't input (EOF)
break;
}
}
if(!end)
printf("\nLine-%d: %s\n", line, str);
fclose(fd);
return 0;
}
You have wrote:
char *str = NULL;
and you used it without initializing:
getline(&str, &bytes, fd);
first you must initialize it:
char *str=(char*)malloc(SIZEOFSTR);
you can add this part in your program instead of your do-while loop. You will be using fscanf() whose arguments are the file pointer, specifier of data type and the variable you want to store.
printf("Enter the line number to read : ");
scanf("%d", &line);
while(line--) {
fscanf(fd,"%s",str);
}
printf("\nLine-%d:%s\n",line,str);

Resources