In the code below, I have saved the values 1 - 9 in an Excel file and I want to insert an "a" between "4" and "5". I have set the pointer to position 7 but it is still inserting it at the end. Please help me understand this.
FILE *ExcelFile = fopen("testdata.csv","a");
if (ExcelFile == NULL)
return -1;
fprintf(ExcelFile,"1 2 3 4 5 6 7 8 9");
fseek (ExcelFile, 7, SEEK_SET );
//printf("pos is %ld bytes\n", pos);
fprintf(ExcelFile,"a");
fclose(ExcelFile);
The reason this does not work is because you are opening the file for appending (the "a" flag in the fopen call). Whenever you write to the file the data you write will always be appended. If your file does not exists before opening, use fopen("testdata.csv","w") instead.
You can't just "insert" the value into a file. You must open a new file, copy the first part of the first file, then your value, then the rest, and then replace the old file with the new one, or, if the file is small, read it into memory, clear the file, and then write the correct file.
Related
I am opening a text file and processing word count function to count words and closing a file.
Next, I open the same file again and store it in the array with limit to word count value in an array.
Here, if I use fopen and fclose just once like in line 1 and 16, my program does not work. But if I open it (line 1) process it then close it (line 10) and open it again (line 12) for second process, my program works. Does it mean that fopen can only handle one process at a time and I have to open it again for second process?
1. fptrr = fopen(fname,"r"); // open the text file in read mode
2.
3. if (fptrr == NULL) {//if file name does not match
4. printf("Error: No such file or directory");
5. return -1;
6. }
7.
8. wordCount += countWords(fptrr); //run word count function and get the value of total words
9.
10. fclose(fptrr); // close the file
11.
12. fptrr = fopen(fname,"r");
13. for(int i=0;i<wordCount;i++){ // define size of loop equal to words in a file
14. fscanf(fptrr, "%s", fileArray[i]); //scan and store in array
15. }
16. fclose(fptrr);
You can do whatever you want to the file while it is open.
I suspect your problem is that you are reading to the end of the file in one set of operations and then you try and read the file again while you are at the end. Look for the rewind() function
To rewind to the start of the file just call rewind(fptrr); after the first countwords. Alternately you can call fseek(fptrr, 0L, SEEK_SET) but rewind() is clearer.
Note that closing the file and re-opening it automatically resets the file to read form the start which is why your new version works.
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.
The following code create a file file.text and prints the following in the file "
1 2
3 4
What is the most efficient way to print the value 4 on the console. In actual case I have a 2000 x 2000 matrix, and I have to access let say the value [2000][1500] and print the same on console. by efficient I mean how quickly the pointer can go there, fetch the data, and send it to the display buffer.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp;
fp = fopen ("file.txt", "w+");
fprintf(fp, "%s %s %s %d", "1", "2", "\n" "3", 4);
fclose(fp);
return(0);
}
Assuming the "file" need not be a text file, and the data to be stored need not be formatted in the form of matrix (i.e. including spaces and newlines).
You can do the following:
Step 1. Open file in binary mode.
Step 2. Write the matrix (suppose A[2000][2000])data in the file using fwrite.
Step 3. Now your file is ready, you want to read element at position say [1500][1000].
Step 4. That will be ((1500*2000) + 1000)th integer written in the file, so use fseek to get the file pointer to that position.
Step 5: Read the integer from that position using fread.
I have opened one file with following way:
fp = fopen("some.txt","r");
Now in this file the 1st some bytes lets say 40 bytes are unnecessary junk of data so I want to remove them. But I cannot delete that data from that file, modify or
create duplicates of that file without that unnecessary data.
So I want to create another dummy FILE pointer which points to the file and when I pass this dummy pointer to any another function that does the following operation:
fseek ( dummy file pointer , 0 , SEEK_SET );
then it should set the file pointer at 40th position in my some.txt.
But the function accepts a file descriptor so i need to pass a file descriptor which will treat the file as those first 40 bytes were never in the file.
In short that dummy descriptor should treat the file as those 40 bytes were not in that file and all positioning operations should be with respect to that 40th byte counting as the is 1st byte.
Easy.
#define CHAR_8_BIT (0)
#define CHAR_16_BIT (1)
#define BIT_WIDTH (CHAR_8_BIT)
#define OFFSET (40)
FILE* fp = fopen("some.txt","r");
FILE* dummy = NULL;
#if (BIT_WIDTH == CHAR_8_BIT)
dummy = fseek (fp, OFFSET*sizeof(char), SEEK_SET);
#else
dummy = fseek (fp, OFFSET*sizeof(wchar_t), SEEK_SET);
#endif
The SEEK_SET macro indicates beginning of file, and depending on whether you are using 8-bit characters (ASCI) or 16-bit characters (eg: UNICODE) you will step 40 CHARACTERS forward from the beginning of your file pointer, and assign that pointer/address to dummy.
Good luck!
These links will likely be helpful as well:
char vs wchar_t
http://www.cplusplus.com/reference/clibrary/cstdio/fseek/
If you want, you can just convert a file descriptor to a file pointer via the fdopen() call.
http://linux.die.net/man/3/fdopen
fseek ( dummy file pointer , 0 , SEEK_SET );
In short that dummy pointer should treat the file as there is no that 40 byte in that file and all position should be with respect to that 40th byte as counting as it is 1st byte.
You have conflicting requirements, you cannot do this with the C API.
SEEK_SET always refers to the absolute position in the file, which means if you want that command to work, you have to modify the file and remove the junk.
On linux you could write a FUSE driver that would present the file like it was starting from the 40th byte, but that's a lot of work. I'm only mentioned this because it's possible to solve the problem you've created, but it would be quite silly to actually do this.
The simplest thing of course would be just to abandon this emulating layer idea you're looking for, and write code that can handle that extra header junk.
If you want to remove the first 40 bytes of a file on the disk without creating another file, then you can copy the content from the 41th byte and onwards into a buffer, then write it back at offset -40. Then use ftruncate (a POSIX library in unistd.h) to truncate at (filesize - 40) offset.
I wrote a small code with what i understood from your question.
#include<stdio.h>
void readIt(FILE *afp)
{
char mystr[100];
while ( fgets (mystr , 100 , afp) != NULL )
puts (mystr);
}
int main()
{
FILE * dfp = NULL;
FILE * fp = fopen("h4.sql","r");
if(fp != NULL)
{
fseek(fp,10,SEEK_SET);
dfp = fp;
readIt(dfp);
fclose(fp);
}
}
The readIt() is reading the file from the 11 byte.
Is this what you are expecting or something else?
I haven't actually tried this, but I think you should be able to use mmap (with the MAP_SHARED option) to get your file mapped into your address space, and then fmemopen to get a FILE* that refers to all but the first 40 bytes of that buffer.
This gives you a FILE* (as you describe in the body of your question), but I believe not a file descriptor (as in the title and elsewhere in the question). The two are not the same, and AFAIK the FILE* created with fmemopen does not have an associated file descriptor.
Here is the problem: I have to change header of WAVE file, to be exact I have to change ChunkSize and SubChunk2Size. The problem is that those values use 4bytes but it seemt that using fwrite i overwrite 8 bytes:
the original:
RIFFđ WAVEfmt
edited:
RIFF(} } fmt
code:
FILE *nova;
nova=fopen ( "nova.wav", "wb" );
fseek ( nova, 4, SEEK_SET );
fwrite ( &brojacC,4,1,nova );
fseek ( zvuk, 44, SEEK_SET );
fwrite ( &brojacCS2,4,1,nova );
In edited file WAVE is overwritten. Something went wrong because I started at 4th byte and wrote 4 bytes and WAVE starts at 8th byte.
I hope I was at least a bit clear. Can this be done in some other way?
Well, according to my man fopen output:
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 cre‐
ated 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.
That being said, I would definitely go forfopen("nova.wav", "r+b"), as w seems to truncate the file, and you're reading before writing, while a appends to the end of the file, and you want to rewrite part of the file.
This code has at least one bug on every line shown.
FILE *nova;
It is easier to get the error handling right if you do this sort of thing with open, write, and lseek rather than fopen, fwrite, and fseek.
nova=fopen ( "nova.wav", "wb" );
The second string should be "r+b" instead of "wb" so you don't truncate the file. You need to check for errors.
fseek ( nova, 4, SEEK_SET );
You need to check for errors.
fwrite ( &brojacC,4,1,nova );
fwrite should always be called with second argument 1 and third argument equal to the size of the data to be written; otherwise it is impossible to recover from short writes. You need to check for short writes and write errors.
You don't show the code that initializes brojacC so I can't assess whether you have any endianness or structure-padding problems, but I bet you do.
fseek ( zvuk, 44, SEEK_SET );
This operates on the unrelated file handle zvuk rather than nova. And you need to check for errors.
fwrite ( &brojacCS2,4,1,nova );
Since the fseek call on the previous line was applied to zvuk, this writes at offset 4+4=8, not offset 44 as was intended. All the comments on the previous fwrite line also apply to this line. (Psst: You need to check for errors.)
Inconsistent spacing around commas, by the way, invites the gods to strike you with lightning. So does putting spaces on the inside of your parentheses.