Moshe Zadka wrote:
> Here is a small program I wrote because I needed to use
> it.
>
> It takes a file, and splits it into pieces, whose size
> is specified on the command line.
>
> I named it hack because:
> 1. It is. (A hack!).
> 2. It hacks the file into pieces brutally.
> 3. All the good names (cut, split) were taken.
>
> Share, read and enjoy. I'm putting it in the public domain.
Any particular reason why you couldn't use `split'?
You didn't ask for comments, but I'm going to give them to you anyway.
+ #include <stdio.h> /* for fopen, fprintf, sprintf etc */
+ #include <stdlib.h> /* for atoi, exit */
> int main(int argc, char **argv)
> {
- char name[1024];
+ char *name; /* I'll deal with this later. */
- int size;
+ size_t size;
> int count;
> int c;
> FILE *fin;
> FILE *fout;
>
- if(argc<3) {
- fprintf(stderr, "Error usage\n");
+ if(argc != 3) {
+ fprintf(stderr, "Usage %s <size> <filename>\n", argv[0]);
> exit(1);
> }
>
- size=atoi(argv[1]);
+ size=atol(argv[1]);
- fprintf(stderr, "size is %d\n", size);
+ #if _DEBUG_
+ fprintf(stderr, "size is %lu\n", (unsigned long) size);
+ #endif
Likewise, all of the other debugging fprintf() calls should be
conditional.
>
> if((fin=fopen(argv[2], "r"))==NULL) {
- fprintf(stderr, "Error file\n");
+ fprintf(stderr, "Error opening file '%s'\n", argv[2]);
> exit(1);
> }
> fprintf(stderr, "opened %s\n", argv[2]);
>
- if(feof(fin))
- fprintf(stderr, "Empty file\n");
This won't work. feof() doesn't return non-zero until *after* you've
tried to read past EOF.
> for(count=0;!feof(fin);count++) {
- int i;
+ size_t i;
- sprintf(name, "%s.%03d", argv[2], count);
+ sprintf(name, "%1019s.%03d", argv[2], count);
This avoids a potential buffer overrun with filenames longer than 1024
characters. A better solution would be to allocate `name' using
char *name = alloca(strlen(argv[2]) + 5);
This will work regardless of the length of the filename.
> fprintf(stderr, "opening %s\n", name);
> if((fout=fopen(name, "w"))==NULL) {
- fprintf(stderr, "Error out file\n");
+ fprintf(stderr, "Error opening file '%s'\n", name);
> exit(1);
> }
> fprintf(stderr, "opened %s\n", name);
- for(i=0;i<size;i++) {
- if((c=fgetc(fin))!=EOF)
- fputc(c, fout);
- else
- break;
- }
No way.
+ char buff[BUFSIZ];
+ for(i=size; i>0; i-=BUFSIZ) {
+ size_t n = fread(buff, 1, min(i,BUFSIZ), fin);
+ if (n <= 0)
+ break;
+ if (fwrite(buff, 1, n, fout) != n)
+ {
+ fprintf(stderr, "Error writing file\n");
+ exit(1);
+ }
+ if (n < BUFSIZ)
+ break;
+ }
This will copy the data a block at a time, which is substantially more
efficient that copying it a byte at a time.
However, there is still inefficiency caused by the buffering of the
stdio functions. Either use `setvbuf(fp, NULL, _IONBF, 0)' to disable
buffering, or better still, use the POSIX unbuffered I/O functions
(open, read, write, close) rather than the ANSI buffered I/O
functions. Another problem with the ANSI functions is that they aren't
guaranteed to set `errno' appropriately when an error occurs.
> fclose(fout);
> fprintf(stderr, "closed %s\n", name);
> }
+ return 0;
main() returns an `int'.
> }
--
Glynn Clements <[EMAIL PROTECTED]>
split.c