1

I have a binary file from which I want to delete first n characters before further processing. I have file pointer as input.

I tried to use ftruncate but for that I had to create another file pointer which I don't want. I tried below code but it does not help.

#include <stdio.h>
#include <unistd.h>

int main(void) {

        FILE*f,ftemp;
        f=fopen("./temp","a");
        scanf("%d",&n);
        fseek(f,n,SEEK_SET);
        ftruncate(fileno(f),/*end of file*/ );
        ftemp=f;
        return 0;
}

Please suggest any other way.

Actually the first n bytes are binary and rest of the part is like asn.

Thanks

7
  • 3
    To delete characters from a file, other than from the very end of the file, you're going to need to write the results to a new file, omitting the characters you want to delete. Or, you might be able to open the file read/write (you opened yours as append) and carefully read and write blocks of up to n characters, seeking back and forth, then truncate by n at the end of the process, which is all riskier. It's simpler and probably more efficient just to use a new file. You can't simply delete characters from the file. Commented Jan 7, 2016 at 14:27
  • 1
    I'm not sure: Do you want to actual delete the first n bytes permanently from the file, or do you want to just skip them? Commented Jan 7, 2016 at 14:28
  • i want to delete it permanently. Actually there is asn format file in which n characters are header and third party function (which i can't modify ) are unable to read it so i want to delete these characters. Commented Jan 7, 2016 at 15:04
  • i can't change name of file , since there are further checks in which it verifies file name. Commented Jan 7, 2016 at 15:06
  • but you wouldn't change the name permanently, imagine it is like having a temporary copy of it Commented Jan 7, 2016 at 15:08

2 Answers 2

2

Here is a program which will lop off the first N bytes of ./temp, leaving the original file as ./temp-old. It assumes the file will fit in memory. You specify N on the command line.

/*
 * THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 * EITHER EXPRESSED OR IMPLIED.
 */
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#define ERR (-1)

int main (
        int     argc,
        char ** argv
) {
        int             fdin;
        int             fdout;
        unsigned long   n;
        struct stat     st;
        size_t          sz;
        ssize_t         ssz;
        char *          data;

        if (argc != 2) {
                fprintf(stderr, "usage: %s nbytes\n", argv[0]);
                return 1;
        }
        n = strtoul(argv[1], NULL, 10);
        if (errno) {
                fprintf(stderr, "nbytes (%s) is suspect\n", argv[1]);
                return 1;
        }
        fdin = open("./temp", O_RDONLY, 0);
        if (fdin == ERR) {
                fprintf(stderr, "open input: %s\n", strerror(errno));
                return 1;
        }
        if (fstat(fdin, &st) == ERR) {
                fprintf(stderr, "stat input: %s\n", strerror(errno));
                return 1;
        }
        sz = st.st_size;
        if (sz < n) {
                fprintf(stderr, "file is not that big\n");
                return 1;
        }
        data = malloc(sz);
        if (data == NULL) {
                fprintf(stderr, "insufficient memory\n");
                return 1;
        }
        ssz = read(fdin, data, sz);
        if (ssz < 0) {
                fprintf(stderr, "read input: %s\n", strerror(errno));
                return 1;
        }
        if ((size_t)ssz != sz) {
                fprintf(stderr, "read was short\n");
                return 1;
        }
        (void)close(fdin);
        fdout = open("./temp-new", O_CREAT|O_EXCL|O_WRONLY, st.st_mode);
        if (fdout == ERR) {
                fprintf(stderr, "open output: %s\n", strerror(errno));
                return 1;
        }
        sz -= n;
        ssz = write(fdout, data + n, sz);
        if (ssz < 0) {
                fprintf(stderr, "write output: %s\n", strerror(errno));
                return 1;
        }
        if ((size_t)ssz != sz) {
                fprintf(stderr, "write was short\n");
                return 1;
        }
        if (close(fdout) == ERR) {
                fprintf(stderr, "write close: %s\n", strerror(errno));
                return 1;
        }
        if (link("./temp", "./temp-old") == ERR) {
                fprintf(stderr, "link input: %s\n", strerror(errno));
                return 1;
        }
        if (rename("./temp-new", "./temp") == ERR) {
                fprintf(stderr, "rename output: %s\n", strerror(errno));
                return 1;
        }
        return 0;
}

I wrote it carefully, but, of course you should make a backup copy of your file before using it, just in case...

Sign up to request clarification or add additional context in comments.

1 Comment

Well validated! There are few answers as thorough. As for the cheezy lawyer weasle-words disclaimer.... the jury is still out :)
1

Use the dd utility. One way is to set the block size to be equal to the number of bytes you want to delete, then tell dd to seek one block ahead in the input file:

# N is number of bytes to delete: wherever N is seen
# substitute this value.

dd if=infile of=outfile bs=N seek=1

Now outfile is a copy of infile, but with the first N bytes removed.

The following command will also work; unfortunately, it will perform 1 byte read and write system calls, since the block size is 1 byte:

# N is number of bytes to delete
dd if=infile of=outfile bs=1 seek=N

We can use separate input and output block sizes (ibs and obs) if N is too small to be a good buffering factor, so that at least we write in larger chunks:

# read N at a time, skipping first N; write 64 kB at a time:
dd if=infile of=outfile ibs=N obs=65536 seek=1

We can simulate an in-place deletion by then renaming outfile to infile.

It should be possible to actually do this in place. The following almost works:

dd if=inoutfile of=inoutfile bs=N conv=notrunc skip=1

The only problem is that without the conv=notrunc option, the file is immediately truncated to zero length. The content is gone! And with the option, the file isn't truncated at all after being written.

GNU Coreutils has a truncate command which can be used:

dd if=inoutfile of=inoutfile bs=N conv=notrunc skip=1
truncate -s -N inoutfile

The - prefix on the size argument in truncate means "reduce the size by that many bytes".

1 Comment

truncate() removes bytes at the end of the file, not the beginning.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.