Is there any way to create dummy file descriptor in linux? - c

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.

Related

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)

Clearing file contents only using FILE * [duplicate]

I'm using C to write some data to a file. I want to erase the previous text written in the file in case it was longer than what I'm writing now.
I want to decrease the size of file or truncate until the end. How can I do this?
If you want to preserve the previous contents of the file up to some length (a length bigger than zero, which other answers provide), then POSIX provides the truncate() and ftruncate() functions for the job.
#include <unistd.h>
int ftruncate(int fildes, off_t length);
int truncate(const char *path, off_t length);
The name indicates the primary purpose - shortening a file. But if the specified length is longer than the previous length, the file grows (zero padding) to the new size. Note that ftruncate() works on a file descriptor, not a FILE *; you could use:
if (ftruncate(fileno(fp), new_length) != 0) ...error handling...
However, you should be aware that mixing file stream (FILE *) and file descriptor (int) access to a single file is apt to lead to confusion — see the comments for some of the issues. This should be a last resort.
It is likely, though, that for your purposes, truncate on open is all you need, and for that, the options given by others will be sufficient.
For Windows, there is a function SetEndOfFile() and a related function SetFileValidData() function that can do a similar job, but using a different interface. Basically, you seek to where you want to set the end of file and then call the function.
There's also a function _chsize() as documented in the answer by sofr.
In Windows systems there's no header <unistd.h> but yet you can truncate a file by using
_chsize( fileno(f), size);
That's a function of your operating system. The standard POSIX way to do it is:
open("file", O_TRUNC | O_WRONLY);
If this is to run under some flavor of UNIX, these APIs should be available:
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
According to the "man truncate" on my Linux box, these are POSIX-conforming. Note that these calls will actually increase the size of the file (!) if you pass a length greater than the current length.
<edit>
Ah, you edited your post, you're using C. When you open the file, open it with the mode "w+" like so, and it will truncate it ready for writing:
FILE* f = fopen("C:\\gabehabe.txt", "w+");
fclose(file);
</edit>
To truncate a file in C++, you can simply create an ofstream object to the file, using ios_base::trunc as the file mode to truncate it, like so:
ofstream x("C:\\gabehabe.txt", ios_base::trunc);
If you want to truncate the entire file, opening the file up for writing does that for you. Otherwise, you have to open the file for reading, and read the parts of the file you want to keep into a temporary variable, and then output it to wherever you need to.
Truncate entire file:
FILE *file = fopen("filename.txt", "w"); //automatically clears the entire file for you.
Truncate part of the file:
FILE *inFile("filename.txt", "r");
//read in the data you want to keep
fclose(inFile);
FILE *outFile("filename.txt", "w");
//output back the data you want to keep into the file, or what you want to output.

C, unix and overwriting a char with write(), open() and lseek()

I need to replace the a character in a text file with '?'. It's not working as expected.
The file has contents 'abc' (without quotes) and i've got to use the unix system calls: lseek(), open() and write(). I can't use the standard C file I/O functions.
The plan is to eventually exand this into a more generalised "find and replace" utility.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int file = open("data", O_RDWR); //open file with contents 'abc'
lseek(file,0,0); //positions at first char at beginnging of file.
char buffer;
read(file,&buffer, sizeof(buffer));
printf("%c\n", buffer); // text file containing 'abc', it prints 'a'.
if (buffer == 'a'){
char copy = '?';
write(file,&copy,1); //text file containing 'abc' puts '?' were 'b' is.
}
close(file);
}
The file "data" contains abc, i want to replace a with ? and make it ?bc but i'm getting a?c
read() is reading the right char, but write() is writing to the next char.
Why is this?
Been searching google for hours.
Thanks
The answer is actually embedded in your own code, in a way.
The lseek call you do right after open is not required because when you first open a file the current seek offset is zero.
After each successful read or write operation, the seek offset moves forward by the number of bytes read/written. (If you add O_APPEND to your open the seek offset also moves just before each write, to the current-end-of-file, but that's not relevant at this point.)
Since you successfully read one byte, your seek offset moves from 0 to 1. If you want to put it back to 0, you must do that manually.
(You should also check that each operation actually succeeds, of course, but I assume you left that out for brevity here.)
Your call to read() moves the file pointer forward one byte - i.e. from 0 to 1. Since you're using the same file descriptor ("int file = ...") for reading and writing, the position is the same for reading and writing.
To write over the byte that was just read, you need to lseek() back one byte after
(buffer == 'a')
comes true.
lseek is in the wrong place. Once 'a' has been found it writes '?' in the next available spot (which happens to overwrite 'b'). To fix, you need to change the current position using lseek BEFORE you write.
if (buffer == 'a'){
char copy = '?';
lseek(file,0,SEEK_SET); //positions at first char at beginnging of file.
write(file,&copy,1); //text file containing 'abc' puts '?' were 'b' is.
}

C: editing binary file

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.

File processing in c?

I have been given a raw file that holds several jpg images. I have to go through the file, find each jpg image, and put those images each in a separate file. So far I have code that can find each where each image begins and ends. I also have written code that names several file names I can use to put the pictures in. It is an array: char filename[] , that holds the names: image00.jpg - image29.jpg .
What I cannot figure out is how to open a file every time I find an image, an then close that file and open a new one for the next image. Do I need to use fwrite()? Also, each image is in blocks of 512 bytes, so I only have to check for a new image every 512 bytes once I find the first one. Do I need to add that into fwrite?
So, to summarize my questions, I don't understand how to use fwrite(), if that is what I should be using to write to these files.
Also, I do not know how to open the files using the names I have already created.
Thanks in advance for the help. Let me know if I need to post any other code.
Use fopen(rawfilename, "rb"); to open the raw file for reading. and fread to read from it.
Use fopen(outfilename, "wb"); to open output file for writing and fwrite to write to it.
As mentioned in my comment, you are assigning char *[] to char*, use char filename[] = "image00.jpg"; instead.
Don't forget to close each file after you finish its processing (r/w) (look at fclose() at the same site of other links)
Decide how much bytes to read each time by parsing the jpeg header. Use malloc to allocate the amount of bytes needed to be read, and remember, for each allocation of buffer you need to free the allocated buffer later.
Pretty much any book on C programming should cover the functions you need. As MByD pointed out, you'll want to use the functions fopen(), fwrite(), and fclose().
I imagine your code may include fragments that look something like
/* Warning: untested and probably out-of-order code */
...
char **filename = {
"image00.jpg", "image01.jpg", "image02.jpg",
...
"image29.jpg" };
...
int index = 0;
const int blocksize = 512; /* bytes */
...
index++;
...
FILE * output_file = fopen( filename[index], "wb");
fwrite( output_data, 1, blocksize, output_file );
fclose(output_file);
...

Resources