io-help.txt Documentation for Jeff Fessler's IO routines. There are 3 main routines (in src/io/top directory): io_head() reads the header of files to determine array dimensions. io_read_5d() read 2d,3d,4d, or 5d array from named file io_write_n() write Nd array to a named file The read and write routines are very flexible, so have many arguments. In practice, I rarely use the full generality, but instead usually use some simple macros that call the actual routines. Another advantage of using the simpler macros is that later I could change the interface to the full routines (and the macro definitions) without having to change the vast majority of my programs. For completeness, here are the prototypes of the 3 main routines. /* * io_head() * Extract dimensions of a file. Up to 5 dimensions supported. */ bool io_head( int *pn1, /* return 1st dimension here if non null */ int *pn2, /* ... */ int *pn3, int *pn4, int *pn5, char *file_data_type, /* optional: return file data_type, if known */ bool *flag_offset, /* return 1 if this file has a binary header to skip */ cchar *file, /* in: file name */ cchar *file_type, /* out: type of file ("avs", etc.) from suffix */ cint chat) /* verbosity */ /* * io_read_5d() * Read several frames and planes data from one of several N-D file types. * The output data must be preallocated to hold data of the specified type. */ bool io_read_5d( void *data, /* [n1,n2,i3b-i3a+1,i4b-i4a+1,i5b-i5a+1] */ cchar *data_type, /* desired return type: "byte", "float", etc. */ double *scale_out, /* return scale factor */ cint n1, /* length of 1st dimension */ cint n2, /* ... */ cint n3, cint n4, cint n5, cint i3a, cint i3b, /* [0,...,n3-1] requested data ranges */ int i4a, int i4b, int i5a, int i5b, cchar *file_name, cchar *file_type, /* NULL to infer from suffix, or see below */ cchar *var_name, /* optional variable name, if file has directory */ cbool flag_zero_negs, /* use 1 to have negatives set to zero */ cbool flag_crunch, /* scale bytes to 255 or shorts to 32000 ? */ cint chat) /* * io_write_n() * Write N-D data to one of several file types. * If nz > 0, then "offset" is for frame offset. * If nz = 0, then offset is a plane offset. * The offset option only applies to certain file types. */ bool io_write_n( cchar *file_name_in, cvoid *data, /* [ dims[0] * ... * dims[ndim-1] ] */ cchar *data_type, /* "byte", "short", "int", "float", "double" */ cdouble scale_in, /* scale factor for data (usually unity) */ cint *dims, /* [ndim] */ cint ndim, /* should be >= 2 */ int offset, /* see above */ cchar *file_type, /* NULL to infer from suffix, or see below */ cchar *file_head, /* optional external file for header info */ cchar *var_name, /* optional variable name */ cbool flag_protect, /* if 1, do not overwrite, except 't.fld' */ cint chat) Yes indeed there are too many options for normal use. (But I've used all these options at one point or another.) Here are the macros that I use in 95% of my programs. All of the above and the below is included in my header file "def.h" that you should include at the top of any program that uses these routines. /* * Header: */ #define I5dim(p1, p2, p3, p4, p5, file) \ Call1(io_head, (p1, p2, p3, p4, p5, NULL, NULL, file, NULL, Ichat), file) #define I4dim(p1, p2, p3, p4, file) I5dim(p1, p2, p3, p4, NULL, file) #define I3dim(p1, p2, p3, file) I4dim(p1, p2, p3, NULL, file) /* 4d */ #define Iread4d(type, data, nx, ny, nz, nf, if0, if1, file) \ Islices(type, data, nx, ny, nz, nf, 0, Max((nz)-1,0), if0, if1, file) #define Iread4float(data, nx, ny, nz, nf, if0, if1, file) \ Iread4d("float", data, nx, ny, nz, nf, if0, if1, file) /* 3d */ #define Iread3d(type, data, nx, ny, nz, frame, file) \ Iread4d(type, data, nx, ny, nz, 0, frame, frame, file) #define Iread3float(data, nx, ny, nz, file) \ Iread3d("float", data, nx, ny, nz, 0, file) /* write */ #define Iwrite(file, data, type, dims, ndim, name) \ if (!io_write_n(file, data, type, 1., dims, ndim, \ 0, NULL, NULL, name, True, Ichat)) { \ cchar *Itmpfile = "/tmp/t.fld"; \ if (Streq((file)+strlen(file)-4, ".ppm")) \ Itmpfile = "/tmp/t.ppm"; \ else if (Streq((file)+strlen(file)-4, ".pgm")) \ Itmpfile = "/tmp/t.pgm"; \ Note2("io_write(%s) failed, trying %s", file, Itmpfile)\ if (!io_write_n(Itmpfile, data, type, 1., dims, ndim, \ 0, NULL, NULL, name, True, 9/* Ichat */)) \ Fail2("io_write(%s,%s)", file, Itmpfile) \ } #define Iwrite4(file, data, type, nx, ny, nz, nf, name) { \ int Idims[4]; Idims[0]=nx; Idims[1]=ny; Idims[2]=nz; Idims[3]=nf; \ Iwrite(file, data, type, Idims, 2 + (nz > 0) * (1 + (nf > 0)), name) } #define Iwrite3(file, data, type, nx, ny, nz, name) { \ int Idims[3]; Idims[0]=nx; Idims[1]=ny; Idims[2]=nz; \ Iwrite(file, data, type, Idims, 2 + (nz > 0), name) } #define Iwrite4float(file, data, n1, n2, n3, n4) \ Iwrite4(file, data, "float", n1, n2, n3, n4, NULL) #define Iwrite3float(file, data, nx, ny, nz) \ Iwrite3(file, data, "float", nx, ny, nz, NULL) Ok, that may still look a little bit daunting, so accompanying this file is a complete concrete example "io,example.c" which is a program that reads in an array and scales each element by 10 and then writes it back out.