i am trying to read one byte at a time from a file:
size_t result_new = 1;
char buf6[1];
if( (result_new = fread(buf6, 1, 1, pFile)) != 1)
{
printf("result_new = %d\n", result_new);
printf("Error reading file\n");
exit(1);
}
result_new is becoming 0 and it is printing the error. any idea what can be wrong. im sure pFile is fine.
thanks
According to the documentation:
fread() and fwrite() return the
number of items successfully read or
written (i.e., not the number of
characters). If an error occurs, or
the end-of-file is reached, the
return value is a short item count (or zero).
So why don't you check error code that will answer your question? You can use perror, for example.
If you only need one byte, getc would be a much better choice than fread. The interface is simpler and it's likely to be a lot faster.
http://www.cplusplus.com/reference/clibrary/cstdio/fread/ has an example with reading from a file. It is a c++ page but should work for c
Keep in mind when using fread and fwrite that strange errors can occur in some cases when the file is opened for normal text writing. Opening the file for binary will eliminate this potential problem. It's mainly due to "new lines", which seem for some reason to differ between binary and text file reading and writing.
Related
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.
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)
Do any of you guys know if it's possible to update a text file(e.g something.txt) in C?
I was expecting to find a function with similar syntax as update_txt(something.txt), but I haven't found anything while browsing the internet for the last 2 hours.....
The thing is that I would like some data to be stored and displayed in real time in an already opened text file. I can store the data but I am unable to find a way to display it without manually closing the text file and then open it again...
Do someone know how to solve this issue? Or do you have another way to solve it? I have read something about transferring data to a new text document and then renaming it, but I am quite sure that this wouldn't solve my problem. I have also read something about macros that could detect changes in the document and then somehow refresh it. I have never worked with macros and I have absolutely no idea of how they are implemented....
But please tell me if it is a fact that it is impossible to update an already opened text document?
I am thankful for any suggestions or tutorials that you guys may provide! :)
That's outside the scope of C; it will require some system-specific filesystem monitoring mechanism. For example, inotify offers this functionality
First off, you can use the rewind(), fseek(), ftell() or fgetpos() and fsetpos() functions to locate the read pointer in a file. If you record the start position where the updated record was written (the start offset) using ftell() or fgetpos(), you could jump back to that position later with fseek() or fsetpos() and read in the changed data.
The other gotcha lurking here is that in general, you can't simply 'update' a text file. Specifically, if the replacement text is not the same length as the original text, you have problems. You either need to expand or contract the file. This is normally done by making a copy with the desired edit in the correct location, and then copying or moving the modified copy of the file over the original file.
Detecting when some other process modifies the file is harder still. There are different mechanisms in different operating systems. For Linux, it is the inotify system, for example.
Based upon your statement that you 'can't display it without manually closing the text file and open it again', it may be a buffer issue. When using the C standard library calls (fopen, fread, fwrite, fclose, etc ...) the data you write may be buffered in user-space until the buffer is full or the file is closed.
To force the C library to flush the buffer, use the fflush(fp) call where fp is your file pointer.
Regarding: But please tell me if it is a fact that it is impossible to update an already opened text document? Yes, it is not possible, unless you own the handle to the file (i.e. FILE *fp = fopen("someFilePath", "w+");)
Regarding: if it's possible to update a text file(e.g something.txt) in C?
Yes. If you know the location of the file, (someFileLocation, eg. "c:\dev\somefile.txt"), then open it and write to it.
A simple function that uses FILE *fp = fopen(someFileLocation, "w+"); (open existing file for append) and fclose(fp); will do that: Here is an example that I use for logging:
(Note, you will have to comment out, or create the other functions this one refers to, but the general concept is shown)
int WriteToLog(char* str)
{
FILE* log;
char *tmStr;
ssize_t size;
char pn[MAX_PATHNAME_LEN];
char path[MAX_PATHNAME_LEN], base[50], ext[5];
char LocationKeep[MAX_PATHNAME_LEN];
static unsigned long long index = 0;
if(str)
{
if(FileExists(LOGFILE, &size))
{
strcpy(pn,LOGFILE);
ManageLogs(pn, LOGSIZE);
tmStr = calloc(25, sizeof(char));
log = fopen(LOGFILE, "a+");
if (log == NULL)
{
free(tmStr);
return -1;
}
//fprintf(log, "%10llu %s: %s - %d\n", index++, GetTimeString(tmStr), str, GetClockCycles());
fprintf(log, "%s: %s - %d\n", GetTimeString(tmStr), str, GetClockCycles());
//fprintf(log, "%s: %s\n", GetTimeString(tmStr), str);
fclose(log);
free(tmStr);
}
else
{
strcpy(LocationKeep, LOGFILE);
GetFileParts(LocationKeep, path, base, ext);
CheckAndOrCreateDirectories(path);
tmStr = calloc(25, sizeof(char));
log = fopen(LOGFILE, "a+");
if (log == NULL)
{
free(tmStr);
return -1;
}
fprintf(log, "%s: %s - %d\n", GetTimeString(tmStr), str, GetClockCycles());
//fprintf(log, "%s: %s\n", GetTimeString(tmStr), str);
fclose(log);
free(tmStr);
}
}
return 0;
}
Regarding: browsing the internet for the last 2 hours. Next time try
"tutorial on writing to a file in C" in Google, it lists lots of links, including:
This one... More On The Topic.
I'm writing a struct into a file, but it returns garbage. Here is my code:
ptFile = fopen("funcionarios.dat", "ab+");
fwrite(&novoFunc, sizeof(strFunc), 1, ptFile);
The values of struct novoFunc, before and after the fwrite are not garbage.
However, when I return the file values:
ptFile = fopen("funcionarios.dat", "rb+");
[...]
fseek(ptFile, i*sizeof(strFunc), SEEK_SET); //on the loop, i goes from 0 to total structs
fread(&funcionario, sizeof(strFunc), 1, ptFile);
printf("Code: %d; Name: %s; Address: %s; CPF: %d; Sales: %d\n", funcionario.codigo, funcionario.nome, funcionario.endereco, funcionario.cpf, funcionario.numVendas);
Any idea why? The code was working fine, and I dont remember doing significative changes.
Thanks in advance
Edit: Struct definition
typedef struct func{
int codigo;
char nome[50];
char endereco[100];
int cpf;
int numVendas;
int ativo;
} strFunc;
Edit2: It just got weirder: it works fine on linux (using netbeans and gcc compiler), but it doesnt on windows (devcpp and codeblocks). Well, the entire code is here:
http://pastebin.com/XjDzAQCx
the function cadastraFucionario() register the user, and when I use listaFuncionarios(), to list all the registered data, it returns the garbage. Here is a print of what listaFuncionarios() returns:
http://img715.imageshack.us/img715/3002/asodfadhf.jpg
Im sorry the code isnt in english
You say: "The code was working fine, and I dont remember doing significative changes."
When it was working fine, it wrote some structures into your file.
Maybe later it was still working fine, and it appended some additional structures at the end of your file. The original data still remained at the beginning of your file. So when you read the beginning of the file, you read the original data. Maybe.
Are you sure that you read garbage? Are you sure that you didn't just read old data?
In your code:
ptFile = fopen("funcionarios.dat", "ab+");
Appending is the right thing to do for some purposes but not for others. Do you need wb+ instead?
This:
it works fine on linux ... but it doesnt on windows
is a big red flag. Windows has "text" files which are different to "binary" files. On Linux and other Unixes, there is no difference.
Two lines in your source stand out:
fopen("funcionarios.dat", "rb+");
and later
fopen("funcionarios.dat", "r+");
That is, sometimes you open the file in "binary" mode, and sometimes in "text" mode. Make sure you always open any file in "binary" mode (that is, with the b in the mode string) if you ever intend to read or write non-text data.
Here are two problems in your function retornaIndice.
while(!feof(ptFile)){
fseek(ptFile, sizeof(strFunc)*i, SEEK_SET);
fread(&tmpFunc, sizeof(strFunc), 1, ptFile);
You aren't checking the result of fread. After reading the last record, eof has not been reached yet, so you will try another read. That read will reach eof and will return 0, but you aren't checking for that 0, so you will use garbage data and will exit the loop the next time the while statement tests it.
if(codigo != 0 && tmpFunc.ativo){
if(tmpFunc.codigo == codigo){
return i;
}
If you detect a problem at this point, you don't close ptFile. The leaked handle shouldn't cause garbage data to be written to the file, but it doesn't inspire confidence either.
Some of your other functions have the same errors.
I am read from a file like this:
#include <stdio.h>
int main() {
FILE *fp = fopen("sorted_hits", "r+");
while(!feof(fp)) {
int item_read;
int *buffer = (int *)malloc(sizeof(int));
item_read = fread(buffer, sizeof(int), 1, fp);
if(item_read == 0) {
printf("at file %ld\n", ftell(fp));
perror("read error:");
}
}
}
This file is big and I got the "Bad file descriptor" error sometimes. "ftell" indicates that the file position stopped when error occurred.
I don't know why it is "sometimes", is that normal? does the problem lie in my code or in my hard disk? How to handle this?
perror prints whatever is in errno as a descriptive string. errno gets set to an error code whenever a system call has an error return. But, if a system call DOESN'T fail, errno doesn't get modified and will continue to contain whatever it contained before. Now if fread returns 0, that means that either there was an error OR you reached the end of the file. In the latter case, errno is not set and might contain any random garbage from before.
So in this case, the "Bad file descriptor" message you're getting probably just means there hasn't been an error at all. You should be checking ferror(fp) to see if an error has occurred.
You seem to be mixing text and binary modes when reading the file.
Normally when you use fread you read from a binary file i.e. fread reads a number of bytes matching the buffer size but you seem to be opening the file in text mode (r+). ftell doesn't work reliably on files opened in text mode because newlines are treated differently than other characters.
Open the file in binary mode (untranslated) instead:
FILE *fp = fopen("sorted_hits", "rb+");
If that's really what your loop looks like, my guess would be that you're probably getting a more or less spurious error because your process is just running out of memory because your loop is leaking it so badly (calling malloc every iteration of your loop, but no matching call to free anywhere).
It's also possible (but a lot less likely) that you're running into a little problem from your (common but nearly always incorrect) use of while (!feof(fp)).
Your all to printf also gives undefined behavior because you've mismatched the conversion and the type (though on many current systems it's irrelevant because long and int are the same size).
Fixing those may or may not remove the problem you've observed, but at least if you still see it, you'll have narrowed down the possibilities of what may be causing the problem.
int main() {
FILE *fp = fopen("sorted_hits", "r+");
int buffer;
while(0 != fread(&buffer, sizeof(int), 1, fp))
; // read file but ignore contents.
if (ferror(fp)) {
printf("At file: %ld\n", ftell(fp));
perror("read error: ");
}
}