Segmentation fault when I fopen - c

I'm new to C file management . My teacher wanted as a homework to create a functon that copy from a source file to destination file . I created but it gives me errors all the time : Segmentation Fault .
void source_to_destination(FILE *source , FILE *destination)
{
char name_source[10], name_destination[10],line[100];
memset(line,0,sizeof(line));
memset(name_source,0,sizeof(name_source));
memset(name_destination,0,sizeof(name_destination));
read_name_file(name_source);
read_name_file(name_destination);
source = fopen(name_source,"r");
destination = fopen(name_destination,"w");
while(fgets(line,sizeof(line),source) != NULL)
{
fputs(line,destination);
}
}

When copying data from one file to another, reading and writing in binary is preferred. There are a number of reasons that reading with line-oriented input functions such as fgets or getline will fail to properly read all characters in a file. Text output functions suffer similar shortcomings (e.g. attempting to write characters outside the printable range or characters that have alternate meaning as ASCII)
Reading and writing from a file in binary mode using fread and fwrite is not any more difficult than using fgets and fputs. However, using fread and fwrite you are guaranteed a correct and accurate copy of your data by avoiding the pitfalls inherent in attempting a general file copy in text mode.
If you know there is nothing but text contained in your source file, then there is nothing wrong with copying it in text mode. That just means you will have to write another function to handle files that are not text. (and generally you don't see different copy routines based on file contents). Reading and writing in binary eliminates all of these considerations.
The following is a short example of a filecopy function that will read all bytes in a file into a buffer and then write the contents of the buffer to your destination file. (a buffered read/write is generally much more efficient and you can easily adjust the buffer size by adjusting MAXS) The function returns the number of bytes copied on success, -1 otherwise. Look it over and let me know if you have any questions:
#include <stdio.h>
#include <stdlib.h>
#define MAXS 256
int filecopy (char *source, char *dest);
int main (int argc, char **argv) {
if (argc < 3) { /* validate 2 arguments given */
fprintf (stderr, "usage: %s file1 file2\n", argv[0]);
return 1;
}
int filesize = 0;
if ((filesize = filecopy (argv[1], argv[2])) == -1) {
fprintf (stderr, "error: filecopy failed.\n");
return 1;
}
printf ("\n copied '%s' -> '%s' ('%d' bytes)\n\n",
argv[1], argv[2], filesize);
return 0;
}
int filecopy (char *source, char *dest)
{
char *buf = NULL; /* buffer used to read MAXS bytes from file */
size_t nbytes = 0; /* number of bytes read from file */
size_t idx = 0; /* file index (length) */
FILE *fp = fopen (source, "r"); /* stream pointer */
if (!fp) { /* open source for reading */
fprintf (stderr, "error: file open failed '%s'.\n", source);
return -1;
}
/* allocate MAXS size read buf initially */
if (!(buf = calloc (MAXS, sizeof *buf))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return -1;
}
/* while data read MAXS *buf from file - realloc for next read */
while ((nbytes = fread (buf+idx, sizeof *buf, MAXS, fp)))
{
idx += nbytes; /* update total bytes read */
if (nbytes < MAXS) break; /* end-of-file reached */
/* full read - realloc for next */
void *tmp;
if (!(tmp = realloc (buf, (idx + nbytes) * sizeof *buf))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
buf = tmp;
}
fclose (fp); /* close input stream */
if (!(fp = fopen (dest, "w+b"))) { /* open output stream */
fprintf (stderr, "error: file open failed '%s'.\n", dest);
exit (EXIT_FAILURE);
}
fwrite (buf, sizeof *buf, idx, fp);
fclose (fp); /* close output stream */
free (buf);
return (int)idx;
}
Compile
gcc -Wall -Wextra -O3 -o bin/filecopy_simple filecopy_simple.c
Input File (binary)
-rw-r--r-- 1 david david 66672 Nov 19 13:17 acarsout2.bin
Use/Output
$ ./bin/filecopy_simple dat/acarsout2.bin dat/acarsout3.bin
copied 'dat/acarsout2.bin' -> 'dat/acarsout3.bin' ('66672' bytes)
Verification
$ ls -al acarsout[23]*
-rw-r--r-- 1 david david 66672 Nov 19 13:17 acarsout2.bin
-rw-r--r-- 1 david david 66672 Dec 13 14:51 acarsout3.bin
$ diff dat/acarsout2.bin dat/acarsout3.bin
$

The following code
compiles cleanly
performs the desire operation (copy a file)
perform appropriate error checking
is getting the file names from the command line
You will need to modify this to get the file names via your existing functions
always cleans up after itself including closing open files
demonstrates how to pass the FILE* variables --into-- the function
the sub function prototype, etc will need to be modified
if you want to open the files in the sub function
then have main() close them.
Here is a suggested method of performing the desired operation
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define MAX_LINE_LENGTH (256)
// prototypes
void source_to_destination(FILE *source , FILE *destination);
int main( int argc, char * argv[] )
{
if( 3 != argc )
{ // not correct number of command line parameters
fprintf( stderr, "USAGE: %s <sourceFili> <destinationFile>\n", argv[0]);
exit( EXIT_FAILURE );
}
// implied else, correct number of arguments
FILE *fp_in = NULL;
if( NULL == (fp_in = fopen( argv[1], "r") ) )
{ // then fopen failed
fprintf( stderr, "fopen for input file: %s failed due to %s\n", argv[1], strerror(errno) );
exit( EXIT_FAILURE );
}
// implied else, fopen input file successful
FILE *fp_out = NULL;
if( NULL == (fp_out = fopen( argv[2], "w") ) )
{ // then fopen failed
fprintf( stderr, "fopen for output file: %s failed due to %s\n", argv[2], strerror(errno) );
fclose( fp_in ); // cleanup
exit( EXIT_FAILURE );
}
// implied else, fopen output file successful
source_to_destination( fp_in, fp_out );
fclose( fp_in );
fclose( fp_out );
return 0;
} // end function: main
void source_to_destination(FILE *source , FILE *destination)
{
char line[ MAX_LINE_LENGTH ];
while(fgets(line,sizeof(line),source) )
{
if( EOF == fputs(line,destination) )
{ // then fputs failed
fprintf( stderr, "fputs to output file failed due to %s\n", strerror(errno) );
fclose( source );
fclose( destination );
exit( EXIT_FAILURE );
}
}
} // end function: source_to_destination

Related

Segfault in getline

The following code is supposed to read the file "rules.txt" and write it to a device line by line.
The flow should be:
Read line from rules.txt
Echo it to device
The following code always end in segfault because of readline and I have no idea why:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define BUFFER_LENGTH 256
int main()
{
char *line;
size_t len = BUFFER_LENGTH;
int fd = open("./rules.txt", O_RDONLY);
if(fd == -1)
{ perror("open failed"); return 0; }
FILE* fout = fopen("/sys/class/Rule_Table_Class/Rule_Table_Class_Rule_Table_Device/sysfs_att", "w+");
if(fout == NULL)
{ close(fd); perror("fopen failed, log.txt is busy!"); return 0; }
while (1)
{
line = (char*) malloc(len*sizeof(char));
if(line==NULL){
perror("malloc failed!"); return 0;
}
int bytesRead = getline(&line, &len, fd);
if (bytesRead == -1)
{
perror("Failed to read the message from the device.");
return errno;
}
sprintf(line,"%s","lala");
printf("line = %s", line);
}
fclose(fout);
close(fd);
return 0;
}
EDIT:
I corrected the code and still get a segfault. Here is the corrected code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define BUFFER_LENGTH 256
int main()
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("./rules.txt", "r");
if(fp == NULL)
{ perror("open failed"); return 0; }
FILE* fout = fopen("/sys/class/Rule_Table_Class/Rule_Table_Class_Rule_Table_Device/sysfs_att", "w+");
if(fout == NULL)
{ perror("fopen failed!"); return 0; }
while (1)
{
ssize_t bytesRead = getline(&line, &len, fp);
if (bytesRead == -1)
{
return 0;
}
printf("line = %s", line);
fprintf(line,"%s",fout);
}
fclose(fout);
fclose(fp);
return 0;
}
First of all, the proper core getline() loop is
/* FILE *in = fopen(..., "r"); */
char *line = NULL;
size_t size = 0;
while (1) {
ssize_t len = getline(&line, &size, in);
if (len < 0)
break;
/* You have 'len' chars at 'line', with line[len] == '\0'. */
}
so, it is not getline() that causes the segfault, it is your fprintf(line, "%s", fout); that should be either fprintf(fout, "%s", line); or just fputs(line, fout);, or fwrite(line, 1, bytesRead, fout); since the line can contain embedded NUL bytes that fprintf() and fputs() consider an end of string mark.
If we modify the code so that the source and target file names are taken as command-line arguments (with - denoting standard input or standard output), this is what I'd personally like to see:
/* SPDX-License-Identifier: CC0-1.0 */
/* This tells the GNU C library to expose POSIX features, including getline(). */
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *self = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", self);
fprintf(stderr, " %s SOURCE TARGET\n", self);
fprintf(stderr, "\n");
fprintf(stderr, "This copies all content from SOURCE to TARGET, line by line.\n");
fprintf(stderr, "Use '-' for standard input source or standard output target.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
const char *srcpath = argv[1];
const char *dstpath = argv[2];
/* If the path is "-", set it to NULL. */
if (srcpath && !strcmp(srcpath, "-"))
srcpath = NULL;
if (dstpath && !strcmp(dstpath, "-"))
dstpath = NULL;
FILE *src, *dst;
/* Open source for reading. If srcpath is NULL, use stdin. */
if (srcpath) {
src = fopen(srcpath, "r");
if (!src) {
fprintf(stderr, "%s: %s.\n", srcpath, strerror(errno));
return EXIT_FAILURE;
}
} else {
src = stdin;
}
/* Open target for writing. If dstpath is NULL, use stdout. */
if (dstpath) {
dst = fopen(dstpath, "w");
if (!dst) {
fprintf(stderr, "%s: %s.\n", dstpath, strerror(errno));
fclose(src);
return EXIT_FAILURE;
}
} else {
dst = stdout;
}
char *line = NULL;
size_t size = 0;
unsigned long linenum = 0;
while (1) {
ssize_t len = getline(&line, &size, src);
if (len < 0)
break;
linenum++;
if (fwrite(line, 1, len, dst) != (size_t)len) {
fprintf(stderr, "%s: Write error on line %lu.\n", dstpath ? dstpath : "(standard output)", linenum);
fclose(dst);
fclose(src);
return EXIT_FAILURE;
}
}
/* Technically, we don't need to release dynamically allocated (non-shared) memory,
because we're just about to exit, and the OS will automagically do that for us.
We can do this at any point we want during the loop, too. */
free(line);
line = NULL;
size = 0;
/* We do not know why getline() returned -1. Check if an error occurred, and whether we're at end of input. */
if (ferror(src) || !feof(src)) {
fprintf(stderr, "%s: Read error on line %lu.\n", srcpath ? srcpath : "(standard input)", linenum);
fclose(dst);
fclose(src);
return EXIT_FAILURE;
}
/* Check if any write errors have occurred. */
if (ferror(dst)) {
fprintf(stderr, "%s: Write error on line %lu.\n", dstpath ? dstpath : "(standard output)", linenum);
fclose(dst);
fclose(src);
}
/* Read errors should not occur at close time, but it costs very little for us to test anyway. */
if (fclose(src)) {
fprintf(stderr, "%s: Read error on line %lu.\n", srcpath ? srcpath : "(standard input)", linenum);
fclose(dst);
return EXIT_FAILURE;
}
/* Write errors can occur at close time, if the output has been buffered, or the target is on
a remote filesystem. Again, it costs us very little to check. */
if (fclose(dst)) {
fprintf(stderr, "%s: Write error on line %lu.\n", dstpath ? dstpath : "(standard output)", linenum);
return EXIT_FAILURE;
}
/* No errors; target is an identical copy of the source file. */
fprintf(stderr, "%lu lines copied successfully.\n", linenum);
return EXIT_SUCCESS;
}
The SPDX-License-Identifier is a common way to indicate the license of the code. I use CC0-1.0, which basically means "use as you wish, just don't blame the author for any issues: no guarantees, no warranties."
The #define _POSIX_C_SOURCE 200809L tells the GNU C library that we want it to expose POSIX.1-2008 features, which include getline(). If you look at man 3 getline, you'll see in the Synopsis section that glibc 2.10 and later require _POSIX_C_SOURCE to be defined to at least 200809L.
Most of the code is to print the usage, and getting the source and target file names from the command line, and handling - as a special name, "standard stream", so that it can be used even in pipes by specifying - as the input and/or output file name.
The getline() loop uses fwrite() to write the line to the target file. This way, if the input contains embedded NUL bytes (\0), the target will still be identical to the source file.
After the loop, we discard the line buffer, although since the program is just about to exit, we could omit that (since the OS will release all dynamically allocated (non-shared) memory when we exit anyway).
I like code that checks with ferror(src) || !feof(src) if an error occurred in src or src did not reach end of input; and that checks the return value of fclose(), in case a delayed (write) error is reported. Granted, fclose() should never fail for a read-only file, and fclose() should only fail for files we've written to in specific circumstances, but it costs very little to check, and this way the user running the program will be told if the program detected loss of data.
I believe it is morally reprehensible to ignore checking for such errors (especially "because they occur so rarely"), since such tests are the only way the human user can know whether the operation was successful, or if some odd problem occurred. It is up to the human to investigate any problems, and up to our programs to report detectable issues.
The getline function takes a FILE * as a parameter, not an int. Replace the following line:
int fd = open("./rules.txt", O_RDONLY);
By;
FILE *fin = fopen("./rules.txt", "r");
Fix the error checking in the following lines accordingly, like you did with fout.
Then replace the line:
int bytesRead = getline(&line, &len, fd);
Instead it should now use fin:
ssize_t bytesRead = getline(&line, &len, fin);
Note that getline returns ssize_t, not int.
You are also never writing to fout, but I guess you're still working on this code.
Make sure to enable compiler warnings, because your compiler would surely have warned you for using an int parameter where a FILE * was expected.

how can i read data from a file then edit it and print it in the same file?

What I'm trying to do is read this text from a file:
Tomorrow, and tomorrow, and tomorrow,
Creeps in this petty pace from day to day,
To the last syllable of recorded time;
And all our yesterdays have lighted fools
The way to dusty death. Out, out, brief candle!
Life's but a walking shadow, a poor player
That struts and frets his hour upon the stage
And then is heard no more. It is a tale
Told by an idiot, full of sound and fury
Signifying nothing.
And change it all to upper case letters.
I can do this if I read the text from one file and print to another.
#include <stdio.h>
#include <ctype.h>
int main() {
FILE* input_file = fopen("some_text.txt", "a+");
char c = fgetc(input_file);
int charc = 0;
int alpha = 0;
while(1){
if(isalpha(c)){
alpha = alpha + 1;
}
charc = charc + 1;
fprintf(input_file,"%c",toupper(c));
c = fgetc(input_file);
if(feof(input_file)){
break;
}
}
fprintf(input_file,"\nTotal Characters: %d, Total alphabetical characters: %d",charc,alpha);
fclose(input_file);
return 0;
}
If you are simply wanting to convert all characters in a file to uppercase and write the results back to the same file, the direct approach is to open the file for reading, get the length of the file and allocate a buffer to hold the entire file and read the entire file into the buffer, and close the file. Then loop over each character in the buffer calling toupper() on each character and converting the buffer to all uppercase. Then open the file again for writing which will truncate the file and then write the entire buffer back out to the file closing the file and freeing the buffer when you are done.
A short example taking the filename to convert as the first argument could be:
Open File in "r" (Read) Mode
...
int main (int argc, char **argv) {
char *filebuf = NULL;
long fplen = 0;
FILE *fp = NULL;
if (argc < 2) { /* validate argument given for filename */
fprintf (stderr, "usage: %s filename\n", argv[0]);
return 1;
}
if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for read */
perror ("fopen-read");
return 1;
}
Determine File Length
fseek (fp, 0, SEEK_END); /* seek end of file */
if ((fplen = ftell (fp)) == -1) { /* get file length */
perror ("ftell-length");
return 1;
}
fseek (fp, 0, SEEK_SET); /* seek beginning */
Allocate Storage for filebuf
/* allocate memory for file */
if (!(filebuf = malloc (fplen * sizeof *filebuf))) {
perror ("malloc-filebuf");
return 1;
}
Read Entire File Into filebuf & Close File
/* read file into filebuf */
if (fread (filebuf, 1, fplen, fp) != (size_t)fplen) {
perror ("fread-filebuf");
return 1;
}
fclose (fp); /* close file after read */
Convert filebuf to UpperCase
for (long i = 0; i < fplen; i++) /* convert all chars toupper */
filebuf[i] = toupper(filebuf[i]);
Open File for Writing "w" Mode & Write filebuf to File & Close
if (!(fp = fopen (argv[1], "w"))) { /* open/validate file open for write */
perror ("fopen-write");
return 1;
}
/* write filebuf to file */
if (fwrite (filebuf, 1, fplen, fp) != (size_t)fplen) {
perror ("fwrite-filebuf");
return 1;
}
if (fclose (fp) == EOF) /* validate close-after-write */
perror ("fclose_after-write");
(note: you always validate close-after-write to catch any error associated with flushing the stream that would not be caught on your validation of fwrite)
Free filebuf Memory
free (filebuf);
That is it in a nutshell. Putting it altogether you could do:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
int main (int argc, char **argv) {
char *filebuf = NULL;
long fplen = 0;
FILE *fp = NULL;
if (argc < 2) { /* validate argument given for filename */
fprintf (stderr, "usage: %s filename\n", argv[0]);
return 1;
}
if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for read */
perror ("fopen-read");
return 1;
}
fseek (fp, 0, SEEK_END); /* seek end of file */
if ((fplen = ftell (fp)) == -1) { /* get file length */
perror ("ftell-length");
return 1;
}
fseek (fp, 0, SEEK_SET); /* seek beginning */
/* allocate memory for file */
if (!(filebuf = malloc (fplen * sizeof *filebuf))) {
perror ("malloc-filebuf");
return 1;
}
/* read file into filebuf */
if (fread (filebuf, 1, fplen, fp) != (size_t)fplen) {
perror ("fread-filebuf");
return 1;
}
fclose (fp); /* close file after read */
for (long i = 0; i < fplen; i++) /* convert all chars toupper */
filebuf[i] = toupper(filebuf[i]);
if (!(fp = fopen (argv[1], "w"))) { /* open/validate file open for write */
perror ("fopen-write");
return 1;
}
/* write filebuf to file */
if (fwrite (filebuf, 1, fplen, fp) != (size_t)fplen) {
perror ("fwrite-filebuf");
return 1;
}
if (fclose (fp) == EOF) /* validate close-after-write */
perror ("fclose_after-write");
free (filebuf);
}
Example Input File
$ cat dat/cj2upper.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Example Use
$ ./bin/fread_file_toupper dat/cj2upper.txt
Resulting Output File
$ cat dat/cj2upper.txt
THIS IS A TALE
OF CAPTAIN JACK SPARROW
A PIRATE SO BRAVE
ON THE SEVEN SEAS.
Look things over and let me know if you have questions. There is more than one way to do this, but this is likely one of the more direct routes.
Almost right, here are some changes to make it work
First open the file in binary mode, this allows you to move in the file with fseek. the rb+ means you can read/write to the file.
Added some error handling if file is not there, always have error handling.
When you write back to the disk, make sure to flush it out to disk since fgetc et al work on a buffer.
fputc is better in this case, since you are anyway just writing one char.
#include <stdio.h>
#include <ctype.h>
int main()
{
char filename[] = "some_text.txt";
FILE* input_file = fopen(filename, "rb+"); // open in binary mode
if ( input_file == NULL ) // some error handling
{
perror(filename);
return -1;
}
int c = fgetc(input_file); // return value is int
int charc = 0;
int alpha = 0;
do
{
if(isalpha(c))
{
alpha = alpha + 1;
}
charc = charc + 1;
// if alpha, then go back one character and rewrite it
if(isalpha(c))
{
fseek(input_file, -1, SEEK_CUR);
fputc(toupper(c),input_file); // use fputc instead of fprintf
fflush(input_file);
}
// read next
c = fgetc(input_file);
}
while (c != EOF);
// at end of file, add some more
fprintf(input_file,"\nTotal Characters: %d, Total alphabetical characters: %d",charc,alpha);
fclose(input_file);
return 0;
}
For performance reason, assuming that most characters will need conversion, make sense to leverage STDIO, which will leverage application level buffering
Example eliminate error checking for readability.
main(...)
{
// Open file
FILE *fp = ... ;
const int BUFFER_SIZE = 1024 ;
char buff[BUFFER_SIZE] ;
while ( 1 ) {
// Read
long loc = ftell(fp) ;
n = fread(buff, 1, sizeof(buff), fp) ;
if ( n <= 0 ) break ;
// Convert
int do_update = 0 ;
for (int i=0 ; i<n; i++ ) {
if ( islower(buff[i] ) {
buff[i] = toupper(buff[i])
do_update = 1 ;
} ;
if(isalpha(c)){
alpha = alpha + 1;
}
charc = charc + 1;
} ;
// Update, only if anything changed
if ( do_update ) {
long next = ftell(fp) ;
fseek(fp, loc, SEEK_SET) ;
fwrite(buff, 1, n, fp) ;
fseek(fp, next, SEEK_SET) ;
} ;
} ;
}

Error message while reading input file - ‘feof’ makes pointer from integer without a cast

I am writing a C program in Ubuntu operating system. I provide an input text file containing string of characters.The program is required to read and manipulate ONE CHARACTER at time and print the whole content of input file in reverse.
When I compile program, I get following error:
reverseFileContent.c: In function ‘main’:
reverseFileContent.c:51:16: warning: passing argument 1 of ‘feof’ makes pointer from integer without a cast [-Wint-conversion]
while(!feof(inputFile))
Can you please explain the error message to me.
Below is the program:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 256
int main (int argc, char *argv[]){
FILE *inputFile, *outputFile;
int fileSize;
int pointer;
char buffer[BUFFER_SIZE];
/* Check for correct user's inputs. */
if( argc !=3 ) {
fprintf(stderr, "USAGE: %s inputFile outputFile.\n", argv[0]);
exit(-1);
}
/* Make sure input file exists. */
if( (inputFile = fopen(argv[1], O_RDONLY))) {
fprintf(stderr, "Input file doesn't exist.\n");
exit(-1);
}
/* Create output file, if it doesn't exist. Empty the file, if it exists. */
if((outputFile = fopen(argv[2], "a+"))) {
fclose(inputFile);
exit(-1);
}
/* Find the size of the input file. */
fileSize = fseek(inputFile, 0, SEEK_END);
/* Read input file and write to output file in reversed order.
* Use lseek() to move the file pointer to the ith position.
* To set the file pointer to a position use the SEEK_SET flag in lseek().
*/
for(pointer=fileSize-1; pointer>=0; pointer--) {
/* INSERT YOUR CODE HERE */
/*
* In a loop:
* - Read input file into a buffer
* Don't read one byte at a time! Try to read BUFFER_SIZE (i.e., 256) bytes at a time.
* - Write content in the buffer to the output file
*/
while(!feof(inputFile))
{
fgets(buffer, BUFFER_SIZE, inputFile); //reads 256 bytes at a time
fputs (buffer , outputFile );
}
}
fclose(inputFile);
fclose(outputFile);
return(0);
}

Reading Long Values From Sysfs Path With Escape Characters

I am using C file IO to read value from a sysfs interface in linux. Path and sample value of the register is as follows:
cat /sys/class/powercap/intel-rapl/intel-rapl\:0/energy_uj
56039694184
Code: Added \ after intel-rapl\ to take into account unknown escape sequence
#define FILE_SIZE 512
static FILE *fp;
char filename[FILE_SIZE];
char TEMP[FILE_SIZE];
int FILE, READ;
long int POWER;
FILE = open("/sys/class/powercap/intel-rapl/intel-rapl\\:0/energy_uj", O_RDONLY);
READ = read(FILE, TEMP, sizeof(TEMP));
POWER= strtod(TEMP,NULL);
close(FILE);
sprintf(filename,"test.csv");
fp = fopen(filename,"a+");
fprintf(fp,"\n");
fprintf(fp, "%ld", POWER);
The code compiles without any error, but in the output file I am getting value as 0. Is this due to how I am taking into account the escape sequence?
Thanks.
Since the sysfs files, while 'files' in one sense, may also be nodes, etc.. and not traditional text files, it is often best to let the shell interact with the sysfs files and simply read the needed values from a pipe following a call to popen using the shell command, e.g.
#include <stdio.h>
int main (void) {
long unsigned energy_uj = 0;
FILE *proc = popen (
"cat /sys/class/powercap/intel-rapl/intel-rapl\\:0/energy_uj", "r");
if (!proc) { /* validate pipe open for reading */
fprintf (stderr, "error: process open failed.\n");
return 1;
}
if (fscanf (proc, "%lu", &energy_uj) == 1) /* read/validate value */
printf ("energy_uj: %lu\n", energy_uj);
pclose (proc);
return 0;
}
Example Use/Output
$ ./bin/sysfs_energy_uj
energy_uj: 29378726782
That's not to say you cannot read from the sysfs files directly, but if you have any problems, then reading from a pipe is fine. For the energy_uj value, it can be read directly without issue:
#include <stdio.h>
int main (void) {
long unsigned energy_uj = 0;
FILE *fp = fopen (
"/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj", "r");
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed.\n");
return 1;
}
if (fscanf (fp, "%lu", &energy_uj) == 1) /* read/validate value */
printf ("energy_uj: %lu\n", energy_uj);
fclose (fp);
return 0;
}
Example Use/Output
$ ./bin/sysfs_energy_uj_file
energy_uj: 33636394660

C: reading a file line by line

Input files have one entry per line and be of the form T S where T is the arrival time and S is the sector to be read.
I have a file.txt where it looks like
1 6
2 7
3 8
Would indicate three disk accesses for sectors 6, 7, and 8 arriving at time 1 2 and 3 respectively.
how do i parse it so that the first number goes to T and the second goes to S?
There are many ways to accomplish this task.
The scanf() (or perhaps fscanf()) method mentioned by pmg is perhaps most commonly taught to new programmers by academia.
The readLine() method, referred to by doniyor is an alternate approach which reads one character at a time to assemble a complete line, which then can be parsed as a string.
You might even try using fgets() to read an entire line, and then parse the numbers out of the line buffer.
The above list of methods is by no means complete. There are many other ways to accomplish the task.
Of course, you have probably have a full working understanding of these common methods, and you are looking for something with some zing! Perhaps the following will help you on your way:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(
int I__argC,
char *I__argV[]
)
{
int rCode=0;
struct stat statBuf;
FILE *fp = NULL;
char *fileBuf = NULL;
size_t fileBufLength;
char *cp;
/* Verify that caller has supplied I__argV[1], which should be the path
* to the datafile.
*/
if(I__argC != 2)
{
rCode=EINVAL;
fprintf(stderr, "Usage: %s {data file path}\n", I__argV[0]);
goto CLEANUP;
}
/* Get the size of the file (in bytes);
* (assuming that we are not dealing with a sparse file, etc...)
*/
errno=0;
if((-1) == stat(I__argV[1], &statBuf))
{
rCode=errno;
fprintf(stderr, "stat(\"%s\", ...) failed. errno[%d]\n", I__argV[1], errno);
goto CLEANUP;
}
/* Open the caller-specified file in read mode. */
errno = 0;
fp=fopen(I__argV[1], "r");
if(NULL == fp)
{
rCode=errno;
fprintf(stderr, "fopen(\"%s\", \"r\") failed. errno[%d]\n", I__argV[1], errno);
goto CLEANUP;
}
/* Allocate a buffer large enough to hold the entire file content. */
fileBuf=malloc(statBuf.st_size);
if(NULL == fileBuf)
{
rCode=ENOMEM;
fprintf(stderr, "malloc(%zd) failed.\n", statBuf.st_size);
goto CLEANUP;
}
/* Read the file into the fileBuf. */
errno=0;
fileBufLength=fread(fileBuf, 1, statBuf.st_size, fp);
if(fileBufLength != statBuf.st_size)
{
rCode=errno;
fprintf(stderr, "fread() failed to read %zd file bytes. errno[%d]\n",
statBuf.st_size - fileBufLength, errno);
goto CLEANUP;
}
/* Parse the fileBuf for specific data. */
for(cp=fileBuf; cp < fileBuf + fileBufLength; ++cp)
{
long arrivalTime;
long sector;
/* Skip leading white-space (if any) */
if(isspace(*cp))
continue;
/* Parse the 'arrival time'. */
arrivalTime=strtol(cp, &cp, 10);
/* Skip leading white-space (if any) */
while(isspace(*cp))
++cp;
/* Parse the 'sector'. */
sector=strtol(cp, &cp, 10);
printf("%ld, %ld\n", arrivalTime, sector);
}
CLEANUP:
/* Free the fileBuf (if it was successfully allocated) */
if(fileBuf)
free(fileBuf);
/* Close the file (if it was successfully opened) */
if(fp)
fclose(fp);
return(rCode);
}

Resources