C - Modifying a file - c

I have a solution here that supposedly opens a file and changes the last character of it. I don't quite understand how this works. Could you please explain?
void readlast()
{
int handle = open("./file.txt", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
if (handle < 0)
{
return;
}
Okay, this part opens the file and if it doesn't work, returns.
First question: Why is a file opening an integer (int handle)? What is being stored in it?
char c='N';
lseek(handle, -2*sizeof(c), SEEK_END);
lseek apparently changes the location of a reader. So I guess this sets the reader to the end of a file(SEEK_END). But why do we need an offset of -2*sizeof(c) if we just want to write one character?
write(handle, &c, sizeof(c));
close(handle);
}
I do understand this last part.
Thank you!

Normally a file descriptor is returned by open() and it is an integer. 0 and 1 are customarily standard I/O.
File size - 2 [octets] is the offset of last character/byte.

Related

Unexpected behaviour of lseek

I am using lseek just to find the size of a file and lseek returns less bytes than the file's actual size. I think the code is right and I can't explain why that happens.
When i ran the program for the first time it worked well. Then I added some data to the file so it changed its size. Since then, when I run the program again with the new file, the result is always the size of the old file.
Any help appreciated!
int main(int argc,char* argv[]){
int out_file_size=0;
int fd_prognameout;
fd_prognameout=open(argv[1],O_RDWR | O_CREAT,00700);
if(fd_prognameout == -1){
perror("Error:");
return(0);
}
lseek(fd_prognameout,0,SEEK_SET);
out_file_size = lseek(fd_prognameout,0,SEEK_END);
lseek(fd_prognameout,0,SEEK_SET);
printf("The size of out file is: %d\n",out_file_size);
close(fd_prognameout);
return(0);
}
First, lets change these lines
lseek(fd_prognameout,0,SEEK_SET);
out_file_size = lseek(fd_prognameout,0,SEEK_END);
lseek(fd_prognameout,0,SEEK_SET);
to
//get the current file position
off_t current_pos = lseek(fd_prognameout,0,SEEK_CUR);
//get the last position (size of file)
off_t out_file_size = lseek(fd_prognameout,0,SEEK_END);
//reset to the previous position
lseek(fd_prognameout,current_pos,SEEK_SET);
Now to your problem. Modifications to a file might not be immediately visible (due to caching/buffering by the kernel).
After modifying a file, either run the command sync or call in your code the functions fsync() or fdatasync().

How to store the value of stdin into an array in C?

I'm facing a problem to store a file coming from the standard input into a buffer.
Here is my code :
//Go to the end of stdin and calculate the number of elements
int num;
fseek (stdin, 0, SEEK_END);
num = ftell (stdin);
//If there is a file in the standard input
if(num > 0) {
int resRead;
//Read the file and store it into buffer
if((resRead = read(STDIN_FILENO,buffer,num))){
fprintf(stderr, "Error: Could not store the input into buffer\n");
}
//Display the buffer
for (int i = 0; i < num; ++i)
{
printf("%c\n",buffer[i]);
}
}
When i launch my code : ./interpreter < file.txt, i don't get the content of the buffer.
I've to precise that my file has content and when i check the value of num it correspond exactly to the number of char in the file.
Any ideas ? :)
Thank you !!
Operating system level streaming or indirection of a file to a binary does not work in this scenario unless you have file reading code from standard input in your program.
Better option is keep the file in directory and pass the file location as parameter to your program. And use fopen() to read the file.
stdin is a stream, which means that it doesn't have an "end" that you can seek to. There's no way to know if it received a redirected file or if it's reading user input from the console.
You need to dynamically allocate space for your buffer using malloc and read in up to as many bytes as you can fit. If there's still more data, use realloc to expand the buffer (a good strategy is to double the size each time) and read more.
If you know you'll always be reading from a file, you should change the program to take the file name from the command line and use fopen to open the file.

Reading from file in C using fread

I'm learning how to read content from a file in C. And I manage to scrape through the following code.
#include <stdio.h>
#include <stdlib.h>
void read_content(FILE *file) {
char *x = malloc(20);
// read first 20 char
int read = fread(x,sizeof(char),20,file);
if (read != 20) {
printf("Read could not happen\n");
}
else {
printf("the content read is %s",x);
}
free(x);
return;
}
int main(int argc,char *argv[]) {
FILE *fp;
fp = fopen("test.txt","w+");
read_content(fp);
fclose(fp);
return 0;
}
But for some reason (which I'm not able to understand) I see the read bytes count as 0.
The problem is that you open the file with the w+ mode. There are two possibilities:
if the file doesn't exist, it will be created empty. Reading from it immediately gives end of file resulting in fread() returning 0.
if the file does exist, it will be truncated i.e. changed into an empty file. Reading from it immediately gives end of file resulting in fread() returning 0.
If you just want to read from the file (as per your example), open it in mode r. If you want to read and write without destroying its existing content, use mode r+.
Whatever mode you choose, always check that fopen() returns non null and print the error if it returns null (this is not the cause of your problem but is best practice).
From Man Page w+ flag:
Open for reading and writing. The file is created if it does
not exist, otherwise it is truncated.
You are probably trying to open a file which doesn't exist at the path you provided, or is read-only as #WhozCraig suggested in comment. This means a new file is being created, an empty file! hence you are seeing 0 bytes read.
To sum up, The fopen is failing, in that case you need to check the return value if it is equal to -1.
To find what was the error, you can check the errno as it is set to
indicate the error.
If you are only intending to read, open the file with r flag instead of w+
The problem lies within this line of code:
fp = fopen("test.txt","w+")
the "w+" mode, clear the previous content of the file and the file will be empty when you just going to read the file without writing anything to it. Hence, it is printing "Read could not happen" because you are trying to read an empty file.
I would suggest you to use "r+" mode, if you are willing to read and then write into the file. Otherwise, r mode is good enough for simple reading of a file.

How to duplicate an image file? [duplicate]

I am designing an image decoder and as a first step I tried to just copy the using c. i.e open the file, and write its contents to a new file. Below is the code that I used.
while((c=getc(fp))!=EOF)
fprintf(fp1,"%c",c);
where fp is the source file and fp1 is the destination file.
The program executes without any error, but the image file(".bmp") is not properly copied. I have observed that the size of the copied file is less and only 20% of the image is visible, all else is black. When I tried with simple text files, the copy was complete.
Do you know what the problem is?
Make sure that the type of the variable c is int, not char. In other words, post more code.
This is because the value of the EOF constant is typically -1, and if you read characters as char-sized values, every byte that is 0xff will look as the EOF constant. With the extra bits of an int; there is room to separate the two.
Did you open the files in binary mode? What are you passing to fopen?
It's one of the most "popular" C gotchas.
You should use freadand fwrite using a block at a time
FILE *fd1 = fopen("source.bmp", "r");
FILE *fd2 = fopen("destination.bmp", "w");
if(!fd1 || !fd2)
// handle open error
size_t l1;
unsigned char buffer[8192];
//Data to be read
while((l1 = fread(buffer, 1, sizeof buffer, fd1)) > 0) {
size_t l2 = fwrite(buffer, 1, l1, fd2);
if(l2 < l1) {
if(ferror(fd2))
// handle error
else
// Handle media full
}
}
fclose(fd1);
fclose(fd2);
It's substantially faster to read in bigger blocks, and fread/fwrite handle only binary data, so no problem with \n which might get transformed to \r\n in the output (on Windows and DOS) or \r (on (old) MACs)

Ansi C: Attempting to count total chars in a file

The task is simple but I am having an issue with the method returning 0.
This means my loop:
int getCharCount(FILE *fp) {
int c;
int i = 0;
while( (c = fgetc(fp)) != EOF) {
i++;
printf("Loop ran");
}
return i;
}
Did not run.
In my testing I found that the loop never runs because the "Loop ran" never prints. I am new to c and not sure if I am doing something wrong when trying to count chars in the file.
I feel like I should mention that the file is opened with "wb+" mode and that there are a few long methods that edit the file. Essentially before using this getCharCount() method the text file is cleared of all previous data, then user enters a number of 44 char length strings at a time and I use this method I just posted to calculate the total number of chars which will be used to navigate my display data method.
I am in a library working on this so if anything extra is needed to be posted or if anything needs to be clarified I will try to be quick with my responses. I don't want to post my whole code because there would be a chance to cheat and I need to get this done myself.
Thanks ahead.
If you write to the file and then call your method on the same file handle, the file handle is already at the end of the file so it will see EOF immediately. We would need to see more of the code to be sure I think.
So, you could rewind the file handle at the start of your function.
Or you could just call ftell to find out your offset in the file, which is the same as the number of bytes written if you truncate, write and do not rewind.
Why you have to read all bytes one by one to count them? It is much easier to do fseek( fp, 0, 2 ) to jump at end of file and get current position (file length) with ftell( fp ).
You are opening with the mode w+ which will truncate the file. From the fopen man page:
w+ Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
You will want to open it with rb+ instead of wb+ if you are reading from a file and still want to write to it. If you have already written to it and want to read what was written, you will need to seek to the start of the file pointer.
// Both of these seek to the start
rewind(fp);
fseek(fp, 0, SEEK_SET);
If the file is not open, you could use:
off_t getFileSize(const char *filepath) {
struct stat fileStat;
stat(filepath, &fileStat);
return(fileStat.st_size);
}
If the file is open:
off_t getFileSize(int fd) {
struct stat fileStat;
fstat(fd, &fileStat);
return(fileStat.st_size);
}

Resources