I've written a program that writes information to a file. The output to the file is not in the order that I am expecting. I have a header line and three additional lines with numerical information. The header comes first following by the third, first, and second lines.
Note that the file is open in a mode, not a+. According to various sources, re-positioning operators like fseek() are suppose to be ignored. For a while I was actually getting the third line before the first line after that line was written. If the fseek() line is omitted, the third line actually is written before the header ..
If the fseek() function is left commented (regardless of being in a or a+ mode) the output is as shown in the picture below.
I wrote in a bit of code to see how the output should be written. The text in the file is certainly not what it should be ..
I attempted to use the fseek() function to find the position just before the EOF before each write but to no avail.
I have also noticed that if I use fflush(writeP) then I get the same effect that including the fseek() function would. The file is still out of order as shown, but the third line is no longer before the header line.
What am I missing?
void quickSortHelper(int* num, long startTime, long endTime, int size){
FILE *writeP = fopen(QUICKSORT_FILE, "a");
if(writeP == NULL){
fputs("Error opening file\n", stderr);
exit(1);
}
static int times = 0;
long deltaT; //change in time
if(size < STEPSIZE){//first time, write header to file
printf("Writing header!\n");
fprintf(writeP, " --- QUICKSORT ---\nCOUNT\tTIME\tMEDIAN\n");
}
deltaT = (clock() - startTime)/(CLOCKS_PER_SEC/1000);
//fflush(writeP);
fseek(writeP, -1, SEEK_END);
printf("Writing: %d\t%ld\t%d\n", size, deltaT, findMedian(num, size));
fprintf(writeP, "%d\t%ld\t%d\n", size, deltaT, findMedian(num, size));
if(++times == 3)
fclose(writeP);
return;
}
With the fseek() line commented, the output is:
You do not close writeP the first 3 times when function is called. So, the file is opened by several FILE handles which get closed on exit. The "a" works only for the same FILE handle or when data have reached the disk.
The problem comes from the fact that you open the same file on every function call, but only close it on the third call. I would suggest moving the file opening and closing logic out of that function, and passing the FILE * handle as an argument to the function; this would also avoid having to hard code the call number on which to close into that function.
So the place where you call the function would look something like this:
FILE *writeP = fopen(QUICKSORT_FILE, "w"); // "a" changed to "w"
if (!writeP) {
perror(QUICKSORT_FILE);
exit(1);
}
// perhaps write the header into the file here
for (int i = 0; i < 3; ++i) {
// do the quicksort
write_quicksort_results(writeP, …);
}
(void) fclose(writeP);
Related
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)
I'm trying to implement a program I wrote on my Mac on Windows systems, and I'm running into a lot of trouble with this last function:
/* clearFiles */
// deletes the section files after the program has executed
// skips any sections listed table that don't appear in the body (b/c no file was written for these)
// also deletes the table & body files
void clearFiles(section_t *tableArray, int *skipArray, char *tableName, char *bodyName)
{
int i, status, index;
char str[SECTNAME];
char command[SECTNAME];
index = 0;
// clear section files
for(i=1; tableArray[i].count!=0;i++)
{
if(i!=skipArray[index])
{
strcpy(str, tableArray[i].shortName);
strcat(str,".txt");
status = remove(str);
if(status!=0)
printf("Warning! File %s not deleted.\n", str);
} else index++;
}
// clear table file
status = remove(tableName);
if(status!=0)
printf("Warning! File %s not deleted.\n", tableName);
// clear body file
status = remove(bodyName);
if(status!=0)
printf("Warning! File %s not deleted.\n", bodyName);
}
The program takes a very large file and first splits it into a table of contents file and a body file. It then takes the body and splits it into hundreds of individual section files, from which it performs the actual task of the program. At the end, I want it to delete all of these extra files, because they just clutter up the directory. It works perfectly on my Unix Mac environment, but when I try to run it in Command Prompt on a PC, my remove() function returns -1 for every section file and doesn't delete it (it does, however, successfully delete the table & body files). I also tried a more brute force method by using system(del fileName), but this didn't work either, because it says that the file is being used by another process. I can't figure out why these files might be open, as every time fopen() appears, I follow it up with an fclose(). The exception is when checking if the files are open, I use
if(fopen(fileName,"r")!=NULL){}
Could this be the problem? Is there either a way to check if a file is open without actually opening it, or is there a way to close a file that was checked this way? I tried assigning a dummy pointer to it and coding:
dummy = fopen(fileName, "r");
if(dummy!=NULL){}
fclose(dummy);
But this didn't work either. Is it possible to pass just a file path to the fclose() function (for example, something similar to fclose(C:\users\USER\desktop\fileName.txt)? Also, I know that the program is attempting to delete the correct fileName, because my error message prints the correct names to the command prompt.
Any input is greatly appreciated!!! Thanks.
NOTE:
The tableArray starts at 1 because of a search function implemented in the program that returns an index if found and 0 if not found. In hindsight, it would have been better to return -1 if not found and start the index at zero, but that is a separate issue
UPDATE:
Below is the code used to create the section files:
if(fopen(word, "r")==NULL){
ofile = fopen(word, "w");
fprintf(ofile, "SECTION %s ", section);
//go until end of file or until found the next section
// bug fix: check the section after that, too (in case the next section isn't there)
while(fscanf(spec, "%s", word)!=EOF && !cease)
{
if(strcmp(word,"SECTION")!=0){
fprintf(ofile, "%s ", word);
}
else{
fscanf(spec, "%s", word);
choice = testNumber(spec,word);
for(j=i+1; tableArray[j].count!=0;j++)
if(strcmp(word,tableArray[j].shortName)==0)
cease = 1;
}
}
fclose(ofile);
}
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);
}
This function print the length of words with '*' called histogram.How can I save results into text file? I tried but the program does not save the results.(no errors)
void histogram(FILE *myinput)
{
FILE *ptr;
printf("\nsaving results...\n");
ptr=fopen("results1.txt","wt");
int j, n = 1, i = 0;
size_t ln;
char arr[100][10];
while(n > 0)
{
n = fscanf(myinput, "%s",arr[i]);
i++;
}
n = i;
for(i = 0; i < n - 1; i++)
{
ln=strlen(arr[i]);
fprintf(ptr,"%s \t",arr[i]);
for(j=0;j<ln;j++)
fprintf(ptr, "*");
fprintf(ptr, "\n");
}
fclose(myinput);
fclose(ptr);
}
I see two ways to take care of this issue:
Open a file in the program and write to it.
If running with command line, change the output location for standard out
$> ./histogram > outfile.txt
Using the '>' will change where standard out will write to. The issue with '>' is that it will truncate a file and then write to the file. This means that if there was any data in that file before, it is gone. Only the new data written by the program will be there.
If you need to keep the data in the file, you can change the standard out to append the file with '>>' as in the following example:
$> ./histogram >> outfile.txt
Also, there does not have to be a space between '>' and the file name. I just do that for preference. It could look like this:
$> ./histogram >outfile.txt
If your writing to a file will be a one time thing, changing standard out is probably be best way to go. If you are going to do it every time, then add it to the code.
You will need to open another FILE. You can do this in the function or pass it in like you did the file being read from.
Use 'fprintf' to write to the file:
int fprintf(FILE *restrict stream, const char *restrict format, ...);
Your program may have these lines added to write to a file:
FILE *myoutput = fopen("output.txt", "w"); // or "a" if you want to append
fprintf(myoutput, "%s \t",arr[i]);
Answer Complete
There may be some other issues as well that I will discuss now.
Your histogram function does not have a return identifier. C will set it to 'int' automatically and then say that you do not have a return value for the function. From what you have provided, I would add the 'void' before the function name.
void histogram {
The size of arr's second set of arrays may be to small. One can assume that the file you are reading from does not exceed 10 characters per token, to include the null terminator [\0] at the end of the string. This would mean that there could be at most 9 characters in a string. Else you are going to overflow the location and potentially mess your data up.
Edit
The above was written before a change to the provided code that now includes a second file and fprintf statements.
I will point to the line that opens the out file:
ptr=fopen("results1.txt","wt");
I am wondering if you mean to put "w+" where the second character is a plus symbol. According to the man page there are six possibilities:
The argument mode points to a string beginning with one of the
following sequences (possibly followed by additional characters, as
described below):
r Open text file for reading. The stream is positioned at the
beginning of the file.
r+ Open for reading and writing. The stream is positioned at the
beginning of the file.
w Truncate file to zero length or create text file for writing.
The stream is positioned at the beginning of the file.
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.
a Open for appending (writing at end of file). The file is
created if it does not exist. The stream is positioned at the
end of the file.
a+ Open for reading and appending (writing at end of file). The
file is created if it does not exist. The initial file
position for reading is at the beginning of the file, but
output is always appended to the end of the file.
As such, it appears you are attempting to open the file for reading and writing.
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: ");
}
}