C reading a File in binarymode and write to an output file - c

I created a File of 4000 blocks with a blocksize of 4096 Bytes. I wrote to some specific blocks in this file and now I want to read these blocks and write the result into a new output file.
Therefore I open the file I created in "rb" mode (storeFile) and the outputfile in "wb" mode (outputFile) as follows:
FILE * outputFile=fopen(outputFilename,"wb");
FILE * storeFile=fopen(storeFilename, "rb");
now I am trying to seek for the right position and read all blocks to the new file (outputfile):
for(i=0; i<BlocksUsed; i++)
{
fseek(storeFile,blocksToRead[i]*4096,SEEK_SET);
fread(ptr, 4096,1,storeFile);
fwrite(ptr,4096,1outputFile);
...
rewind(storeFile)
}
unfortunately this code leads to a file which is not the file I wrote to the storeFile.
The files' size is BlockUsed*4096Bytes.
What am I doing wrong?
Thank you in advance!

fseek(storeFile,blocksToRead[i]*4096,SEEK_SET);
int n = fread(ptr, 4096,1,storeFile);
if (n <0)
{printf("read error\n");return -1;}
if(fwrite(ptr,n,1outputFile) != n)
{printf("write error\n"); return -1;}
...
//rewind(storeFile)// no need . since you use fseek

Here's a silly example, but it might help illustrate a few points:
#include <stdio.h>
int
main (int argc, char *argv[])
{
FILE *fp_in, *fp_out;
int c;
/* Check command-line */
if (argc != 3) {
printf ("EXAMPLE USAGE: ./mycp <INFILEE> <OUTFILE>\n");
return 1;
}
/* Open files */
if (!(fp_in = fopen(argv[1], "rb"))) {
perror("input file open error");
return 1;
}
if (!(fp_out = fopen(argv[2], "wb"))) {
perror("output file open error");
return 1;
}
/* Copy bytewise */
while ((c = fgetc(fp_in)) != EOF)
fputc (c, fp_out);
/* Close files */
fclose (fp_out);
fclose (fp_in);
return 0;
}

Related

Reading a pdf file with fread in C does not end up as expected

I am trying to read from a pdf file and write into another file where I run to the problem.
In the while loop, fread reads only 589 bytes which is expected to be 1024 for the first time.
In the second loop, fread reads 0 bytes.
I am sure that the pdf file is beyond 1024 bytes.
Here is a similar problem. The phenomenon is the same. But I do not use strlen() which causes that problem.
So how can I resolve the problem?
My code is here:
#include <stdio.h>
#define MAXLINE 1024
int main() {
FILE *fp;
int read_len;
char buf2[MAXLINE];
FILE *fp2;
fp2 = fopen("test.pdf", "w");
if ((fp = fopen("LearningSpark.pdf", "r")) == NULL) {
printf("Open file failed\n");
}
while ((read_len = fread(buf2, sizeof(char), MAXLINE, fp)) > 0) {
int write_length = fwrite(buf2, sizeof(char), read_len, fp2);
if (write_length < read_len) {
printf("File write failed\n");
break;
}
}
return 0;
}
fopen(filename, "r") is system dependent. See this post on what may happen to the data you read if you are on Windows, for example. Basically it is related to how certain characters are translated on different systems in text mode, ie., \n is "End-of-Line" on Unix-type systems, but on Windows it is \r\n.
Important: On Windows, ASCII char 27 will result in End-Of-File, if reading in text mode, "r", causing the fread() to terminate prematurely.
To read a binary file, use the "rb" specifier. Similarly for "w", as mentioned here, you should use "wb" to write binary data.
Binary files such as pdf files must be open in binary mode to prevent end of line translation and other text mode handling on legacy systems such as Windows.
Also note that you should abort when fopen() fails and you should close the files.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define MAXLINE 1024
int main() {
char buf2[MAXLINE];
int read_len;
FILE *fp;
FILE *fp2;
if ((fp = fopen("LearningSpark.pdf", "rb")) == NULL) {
fprintf(stderr, "Open file failed for %s: %s\n", "LearningSpark.pdf", strerror(errno));
return 1;
}
if ((fp2 = fopen("test.pdf", "wb")) == NULL) {
fprintf(stderr, "Open file failed for %s: %s\n", "test.pdf", strerror(errno));
fclose(fp);
return 1;
}
while ((read_len = fread(buf2, 1, MAXLINE, fp)) > 0) {
int write_length = fwrite(buf2, 1, read_len, fp2);
if (write_length < read_len) {
fprintf(stderr, "File write failed: %s\n", strerror(errno));
break;
}
}
fclose(fp);
fclose(fp2);
return 0;
}

Storing .raw File Data as a Pointer Using C

I am attempting to read a '.raw' file which stores the contents of an image that was taken on a camera using C. I would like to store these contents into a uint16_t *.
In the following code I attempt to store this data into a pointer, using fread(), and then write this data into a test file, using fwrite(), to check if my data was correct.
However, when I write the file back it is completely black when I check it.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define MAX_ROW 2560
#define MAX_COL 2160
int main()
{
char filename[32] = "image1.raw";
FILE * image_raw = fopen(filename, "rb");
fseek(image_raw, 0, 2);
long filesize = ftell(image_raw);
/*READ IMAGE DATA*/
uint16_t * image_data_ptr;
image_data_ptr = (uint16_t *)malloc(sizeof(uint16_t)*MAX_ROW*MAX_COL);
fread(image_data_ptr, sizeof(uint16_t), filesize, image_raw);
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp;
fp = fopen("TEST.raw", "w");
fwrite(image_data_ptr, sizeof(uint16_t), filesize, fp);
fclose(fp);
return 0;
}
There are multiple issues with your code:
lack of error handling.
not seeking the input file back to offset 0 after seeking it to get its size. Consider using stat() or equivalent to get the file size without having to seek the file at all.
not dividing filesize by sizeof(uint16_t) when reading from the input file, or writing to the output file. filesize is expressed in bytes, but fread/fwrite are expressed in number of items of a given size instead, and your items are not 1 byte in size.
not opening the output file in binary mode.
leaking the buffer you allocate.
With that said, try something more like this instead:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
char filename[32] = "image1.raw";
FILE *image_raw = fopen(filename, "rb");
if (!image_raw) {
fprintf(stderr, "Can't open input file\n");
return -1;
}
if (fseek(image_raw, 0, SEEK_END) != 0) {
fprintf(stderr, "Can't seek input file\n");
fclose(image_raw);
return -1;
}
long filesize = ftell(image_raw);
if (filesize == -1L) {
fprintf(stderr, "Can't get input file size\n");
fclose(image_raw);
return -1;
}
rewind(image_raw);
long numSamples = filesize / sizeof(uint16_t);
/*READ IMAGE DATA*/
uint16_t *image_data_ptr = (uint16_t*) malloc(filesize);
if (!image_data_ptr) {
fprintf(stderr, "Can't allocate memory\n");
fclose(image_raw);
return -1;
}
size_t numRead = fread(image_data_ptr, sizeof(uint16_t), numSamples, image_raw);
if (numRead != numSamples) {
fprintf(stderr, "Can't read samples from file\n");
free(image_data_ptr);
fclose(image_raw);
return -1;
}
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp = fopen("TEST.raw", "wb");
if (!fp) {
fprintf(stderr, "Can't open output file\n");
free(image_data_ptr);
return -1;
}
if (fwrite(image_data_ptr, sizeof(uint16_t), numSamples, fp) != numSamples) {
fprintf(stderr, "Can't write to output file\n");
fclose(fp);
free(image_data_ptr);
return -1;
}
fclose(fp);
free(image_data_ptr);
return 0;
}
You have already a great answer and useful comments
anyway, consider that if you want to iterate over your file, loaded in memory as a whole, as an array of unsigned words:
if the file size could be odd what to do at the last byte/word
you may read the file as a whole in a single call, after having the file size determined
fstat() is the normal way to get the file size
get the file name from the command line as an argument is much more flexible than recompile the program or change the file name in order to use the program
The code below does just that:
uses image.raw as a default for the file name, but allowing you to enter the file name on the command line
uses fstat() to get the file size
uses a single fread() call to read the entire file as a single record
A test using the original program file as input:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 20/07/2021 17:40 1067 main.c
PS > gcc -Wall -o tst main.c
PS > ./tst main.c
File is "main.c". Size is 1067 bytes
File "main.c" loaded in memory.
PS > ./tst xys
File is "xys". Could not open: No such file or directory
The C example
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char**argv)
{
const char* default_file = "image.raw";
char f_name[256];
if (argc < 2)
strcpy(f_name, default_file);
else
strcpy(f_name, argv[1]);
FILE* F = fopen(f_name, "rb");
if (F == NULL)
{
printf("File is \"%s\". ", f_name);
perror("Could not open");
return -1;
}
struct stat info;
fstat(_fileno(F),&info);
printf("File is \"%s\". Size is %lu bytes\n", f_name, info.st_size);
uint16_t* image = malloc(info.st_size);
if (image == NULL)
{ perror("malloc() error");
return -2;
};
if (fread(image, info.st_size, 1, F) != 1)
{ perror("read error");
free(image);
return -3;
};
// use 'image'
printf("File \"%s\" loaded in memory.\n", f_name);
free(image);
fclose(F);
return 0;
}

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) ;
} ;
} ;
}

About fwrite() errors in C

Reads the file and multiplies the data by 2. After that, I wrote a
program that writes to another file. This file is a 16-bit file. By
the way, only a certain number is written to the created file. I do
not know why this is happening. Please help me.
C (visual studio 2017)
#define _CRT_SECURE_NO_WARNINGS
#define SIZE 16000
typedef short data_type;
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
FILE *fd, *fd2;
data_type *data;
int n;
data = (data_type*)malloc(sizeof(data_type) * SIZE);
for (int i = 0; i < SIZE; i++)
data[i] = 0;
if ((fd = fopen("C:\\Users\\SeoHyeon\\Documents\\test16kSam16bMono.pcm", "r")) == NULL)
printf("Error opening file1");
if ((fd2 = fopen("C:\\Users\\SeoHyeon\\Documents\\test16kSam16bMono2.pcm", "w")) == NULL)
printf("Error opening file2");
n = fread(data, sizeof(data_type), SIZE, fd);
for (int i = 0; i < SIZE; i++)
data[i] = data[i] * 2.0;
if (fwrite(data, sizeof(data_type), SIZE, fd2) != SIZE) {
printf("Error writing to file.\n");
exit(1);
}
fclose(fd);
fclose(fd2);
free(data);
return 0;
}
It could be that the program is not opening both the files in binary mode.
For example:
FILE *fin = fopen("input_file.bin", "rb"); // <-- Note the "rb"
If your file is opened in text mode, which is the default, if there's an EOF character in the data, the file-input could close prematurely.
EDIT: Also, you should handle the error when your file-handles fd and fd2 are NULL. There's also a couple of other error conditions you aren't checking for, but I leave these as an exercise for the reader.

Sending .amr files to SIM900 over serial in c

I'm trying to send .amr files from my desktop to a SIM900 GSM module over UART.
I'm using teuniz's RS232 library.
I do the initialisation using AT commands and then read the file into a buffer and write it to the UART using the RS232_SendByte() library function byte-by-byte, but it doesn't seem to work.
I send the following AT commands:
AT+CFSINIT
AT+CFSWFILE=\"audio.amr\",0,6694,13000 # After which I get the CONNECT message from the SIM900 module
# Here's where I send the file
AT+CFSGFIS=\"audio.amr\"
Here's my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "rs232.h"
char *readFile(char *filename, int *size) {
char *source = NULL;
FILE *fp = fopen(filename, "rb");
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) { return NULL; }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
if(!source) return NULL;
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { return NULL; }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
free(source);
return NULL;
} else {
source[newLen++] = 0; /* Just to be safe. */
}
*size = bufsize;
}
fclose(fp);
}
return source;
}
int main(int argc, char *argv[])
{
int ret = 0, cport_nr = 2, bdrate=38400;
char data[2000] = {0};
if(RS232_OpenComport(cport_nr, bdrate)) {
printf("Can not open comport\n");
ret = -1;
goto END;
}
int size;
unsigned char *filebuf = readFile("audio.amr", &size);
if (!filebuf) {
ret = -1;
goto END_1;
}
/* Initialization */
RS232_cputs(cport_nr, "AT");
RS232_cputs(cport_nr, "AT+CFSINIT");
sleep(1);
RS232_cputs(cport_nr, "AT+CFSWFILE=\"audio.amr\",0,6694,13000");
/* Wait for CONNECT */
sleep(2);
printf("Sending file of size: %d\n", size);
int i;
for (i = 0; i < size; ++i) {
putchar(filebuf[i]);
RS232_SendByte(cport_nr, filebuf[i]);
}
free(filebuf);
sleep(1);
/* Check if file transferred right */
RS232_cputs(cport_nr, "AT+CFSGFIS=\"audio.amr\"");
END_1:
RS232_CloseComport(cport_nr);
END:
return ret;
}
EDIT 1
Normally, the procedure to send a file to SIM900 using AT commands would be as documented here:
AT+CFSINIT # Initialize flash; Response is OK
AT+CFSWFILE=<filename>,<writeMode>,<fileSize>,<InputTime> # Write file with these parameter; Response is CONNECT; So this is when I start sending the file
Here's where I send the file. If it worked and the sent file size matched the <filesize> sent in the above command, SIM900 must respond with OK, which it doesn't. :(
AT+CFSGFIS=<filename> # Gives the file size on flash. This gives me an error since the file didn't upload correctly.
This leads me to beleive there's something wrong with my program. I'm reading the file in binary mode. And the size reported is exacty the same as I specify in the AT+CFSWFILE=<filename>,<writeMode>,<fileSize>,<InputTime> command.

Resources