|
Application Programming: Files and Input/Output |
|
Normally, unformatted input/output is not portable between different machine architectures because of differences in the way various machines represent binary data. However, it is possible to produce binary files that are portable by specifying the XDR keyword with the OPEN procedures. XDR (for eXternal Data Representation) is a scheme under which all binary data is written using a standard "canonical" representation. All machines supporting XDR understand this standard representation and have the ability to convert between it and their own internal representation.
XDR represents a compromise between the extremes of unformatted and formatted input/output:
The primary differences in the way IDL input/output procedures work with XDR files, as opposed to files opened normally are as follows:
;Open a file for XDR output. OPENW, /XDR, 1, 'data.dat' ;Write a 10-element byte array. WRITEU, 1, BINDGEN(10) ;Close the file and re-open it for input. CLOSE, 1 & OPENR, /XDR, 1, 'data.dat'
then the statement,
;Try to read the first byte only. B = 0B & READU, 1, B
results in the following error:
% READU: Error encountered reading from file unit: 1.
Instead, it is necessary to read the entire byte array back in one operation using a statement such as:
;Read the whole array back at once. B=BYTARR(10) & READU, 1, B
This restriction does not exist for other data types.
IDL uses certain conventions for reading and writing XDR files. If your only use of XDR is through IDL, you do not need to be concerned about these conventions because IDL takes care of it for you. However, programmers who want to create IDL-compatible XDR files from other languages need to know the actual XDR routines used by IDL for various data types. The following table summarizes this information.
The routines used for type COMPLEX, DCOMPLEX, and STRING are not primitive XDR routines. Their definitions are as follows:
bool_t xdr_complex(xdrs, p)
XDR *xdrs;
struct complex { float r, i} *p;
{
return(xdr_float(xdrs, (char *) &p->r) &&
xdr_float(xdrs, (char *) &p->i));
}
bool_t xdr_dcomplex(xdrs, p)
XDR *xdrs;
struct dcomplex { double r, i} *p;
{
return(xdr_double(xdrs, (char *) &p->r) &&
xdr_double(xdrs, (char *) &p->i));
}
bool_t xdr_counted_string(xdrs, p)
XDR *xdrs;
char **p;
{
int input = (xdrs->x_op == XDR_DECODE);
short length;
/* If writing, obtain the length */
if (!input) length = strlen(*p);
/* Transfer the string length */
if (!xdr_short(xdrs, (char *) &length)) return(FALSE);
/* If reading, obtain room for the string */
if (input)
{
*p = malloc((unsigned) (length + 1));
*p[length] = '\0'; /* Null termination */
}
/* If the string length is nonzero, transfer it */
return(length ? xdr_string(xdrs, p, length) : TRUE);
}
The following C program produces a file containing different types of data using XDR. The usual error checking is omitted for the sake of brevity.
#include <stdio.h>
#include <rpc/rpc.h>
[ xdr_complex() and xdr_counted_string() included here ]
main()
{
static struct { /* Output data */
unsigned char c;
short s;
long l;
float f;
double d;
struct complex { float r, i } cmp;
char *str;
}
data = {1, 2, 3, 4, 5.0, { 6.0, 7.0}, "Hello" };
u_int c_len = sizeof(unsigned char); /* Length of a char */
char *c_data = (char *) &data.c; /* Addr of byte field */
FILE *outfile; /* stdio stream ptr */
XDR xdrs; /* XDR handle */
/* Open stdio stream and XDR handle */
outfile = fopen("data.dat", "w");
xdrstdio_create(&xdrs, outfile, XDR_ENCODE);
/* Output the data */
(void) xdr_bytes(&xdrs, &c_data, &c_len, c_len);
(void) xdr_short(&xdrs, (char *) &data.s);
(void) xdr_long(&xdrs, (char *) &data.l);
(void) xdr_float(&xdrs, (char *) &data.f);
(void) xdr_double(&xdrs, (char *) &data.d);
(void) xdr_complex(&xdrs, (char *) &data.cmp);
(void) xdr_counted_string(&xdrs, &data.str);
/* Close XDR handle and stdio stream */
xdr_destroy(&xdrs);
(void) fclose(outfile);
}
Running this program creates the file data.dat containing the XDR data. The following IDL statements can be used to read this file and print its contents:
;Create structure containing correct types.
DATA={S, C:0B, S:0, L:0L, F:0.0, D:0.0D, CMP:COMPLEX(0), STR:''}
;Open the file for input.
OPENR, /XDR, 1, 'data.dat'
;Read the data.
READU, 1, DATA
;Close the file.
CLOSE, 1
;Show the results.
PRINT, DATA
Executing these IDL statements produces the output:
{ 1 2 3 4.00000 5.0000000
( 6.00000, 7.00000) Hello}
For further details about XDR, consult the XDR documentation for your machine. Sun users should consult their Network Programming manual.
IDL Online Help (March 06, 2007)