core/matlab/examples/mex/mexfio64.c

00001 /* Copyright 2003-2006 The MathWorks, Inc. */
00002 
00003 /* This example shows how you can add 64 bit file I/O capability to a
00004  * MEX-file. 64 bit file I/O enables reading and writing data from/to
00005  * large files up to and greater than 2GB (2^31-1 bytes) in size.
00006  * Note that some operating systems or compilers may not yet support
00007  * files larger than 2GB.
00008  */
00009 
00010 #include "io64.h" /* io64.h is required for 64 bit file I/O and it MUST be the
00011         FIRST include in your source file, before system includes */
00012 #include "mex.h"
00013 
00014 /* Some of the techniques used in 32 bit file I/O for files up to 2GB
00015  * do not work for files beyond 2GB in size. This file outlines the
00016  * differences between 32 and 64 bit file I/O and explains each one
00017  * along with examples.
00018  *
00019  * There are 11 important details (functions, integer types,
00020  * struct/data types, suffixes for hardcoded values, format specifiers)
00021  * which comprise 64 bit file I/O:
00022  *
00023  * (1)  int64_T, uint64_T - 64 bit signed and unsigned integer types
00024  *                          (defined in tmwtypes.h)
00025  * (2)  LL, LLU           - suffixes for literal int constants 64 bit values
00026  *                          (C Standard ISO/IEC 9899:1999(E) Section 6.4.4.1)
00027  * (3)  FMT64             - format specifier for printing 64 bit int values
00028  *                          (defined in tmwtypes.h)
00029  * (4)  fopen()           - function to open file and obtain file pointer
00030  *                          (alias for POSIX fopen(), defined in io64.h)
00031  * (5)  setFilePos(),     - function to set the file position for the next I/O
00032  *                          (alias for POSIX fsetpos(), defined in io64.h)
00033  * (6)  getFilePos(),     - function to get the file position for the next I/O
00034  *                          (alias for POSIX fgetpos(), defined in io64.h)
00035  * (7)  fpos_T,           - 64 bit int type for setFilePos() and getFilePos()
00036  *                          (alias for POSIX fpos_t type, defined in io64.h)
00037  * (8)  fileno()          - function to get file descriptor from FILE* pointer
00038  *                          (alias for POSIX fileno(), defined in io64.h)
00039  * (9)  structStat,       - struct to get file size given file pointer or name
00040  *                          (alias for POSIX struct stat, defined in io64.h)
00041  * (10) getFileFstat(),   - function to get file size given file pointer
00042  *                          (alias for POSIX fstat(), defined in io64.h)
00043  * (11) getFileStat()     - function to get file size given file name
00044  *                          (alias for POSIX stat(), defined in io64.h)
00045  */
00046 
00047 void mexfio64cleanup(FILE *fp, char *filename)
00048 {
00049     if ( NULL != fp )
00050     {
00051         mexPrintf("fclose()\n");
00052         fclose(fp);
00053     }
00054 
00055     if ( NULL != filename )
00056     {
00057         mexPrintf("remove() '%s'\n",filename);
00058         remove(filename);
00059     }
00060 }
00061 
00062 /* This is the main MEX function (MEX dynamic library entry point).
00063  */
00064 void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
00065 {
00066     /* (1) int64_T, uint64_T
00067      * (2) LL, LLU
00068      *
00069      * the following example shows how to specify literal 64 bit int
00070      * constants. In UNIX, you must use the LL suffix for signed,
00071      * and LLU for unsigned 64 bit int constants. Note that these suffixes
00072      * are not required for hardcoded (literal) values less than 2GB
00073      * (2^31-1) even if they are assigned to a 64 bit int type.
00074      * These suffixes CANNOT be used in windows and are not necessary
00075      * in windows.
00076      * int64_T and uint64_T are defined in tmwtypes.h as the appropriate
00077      * signed and unsigned 64 bit int types for your platform/OS.
00078      */
00079 
00080 #if defined(_MSC_VER) || defined(__BORLANDC__)
00081     int64_T large_offset_example = 9000222000;
00082 #else
00083     /* use LL suffix for unix constants greater than 2^31-1 signed
00084      * use LLU suffix for unix constants greater than 2^32-1 unsigned
00085      */
00086     int64_T large_offset_example = 9000222000LL;
00087 #endif
00088     int64_T offset   = 0;
00089     int64_T position = 0;
00090     char    str[256];
00091     char    filename[256];
00092     const char *mydata = "hello";
00093 
00094     FILE   *fp;
00095 
00096     (void) plhs;    /* unused parameter */
00097 
00098     /* check inputs */
00099     {
00100         if ( nrhs != 1 )
00101         {
00102             mexErrMsgTxt("One input argument expected (temp filename).");
00103         }
00104 
00105         if ( nlhs > 0 )
00106         {
00107             mexErrMsgTxt("No output arguments expected.");
00108         }
00109 
00110         if ( !mxIsChar(prhs[0]) )
00111         {
00112             mexErrMsgTxt("Temp filename input argument must be a text string.");
00113         }
00114 
00115         if ( mxGetString(prhs[0], filename, sizeof(filename) / 2) )
00116         {
00117             mexErrMsgTxt("mxGetString() failed.");
00118         }
00119     }
00120 
00121     /* (3) FMT64
00122      *
00123      * Note that a 64 bit int cannot be printed with "%d".
00124      * The appropriate format specifier for your platform is defined
00125      * in FMT64, defined in tmwtypes.h
00126      * The following example shows how to print out a large file size.
00127      */
00128 
00129     mexPrintf("Example large file size: %" FMT64 "d bytes.\n",
00130         large_offset_example);
00131 
00132     /* (4) fopen()
00133      *
00134      * just use fopen normally after including io64.h which defines fopen
00135      * correctly to support large file I/O for the platform you're on.
00136      * You don't need to do anything else for fopen.
00137      * No changes at all are required for fread, fwrite, fprintf, fscanf,
00138      * fclose.
00139      */
00140 
00141     /* open existing file for read and update in binary mode */
00142     mexPrintf("fopen() '%s' - ",filename);
00143     fp = fopen(filename,"r+b");
00144     if ( NULL == fp )
00145     {
00146         /* file does not exist - create new file
00147          * for writing in binary mode
00148          */
00149         fp = fopen(filename,"wb");
00150         if ( NULL == fp )
00151         {
00152             sprintf(str,"Failed to open/create test file '%s'",
00153                 filename);
00154             mexErrMsgTxt(str);
00155             return;
00156         }
00157         else
00158         {
00159             mexPrintf("new test file '%s' created\n",filename);
00160         }
00161     }
00162     else mexPrintf("existing test file '%s' opened\n",filename);
00163 
00164     /* get file size - scroll down for getFileFstat() example */
00165     {
00166         structStat statbuf;
00167         int64_T fileSize = 0;
00168 
00169         mexPrintf("getFileFstat() - ");
00170         if ( 0 == getFileFstat(fileno(fp), &statbuf ) )
00171         {
00172             fileSize = statbuf.st_size;
00173             offset = fileSize;
00174             mexPrintf("file size is %" FMT64 "d bytes\n",fileSize);
00175         }
00176         else
00177         {
00178             mexfio64cleanup(fp,filename);
00179             mexErrMsgTxt("getFileFstat() failed.");
00180         }
00181     }
00182 
00183     /* (5) setFilePos(),
00184      * (6) getFilePos(),
00185      * (7) fpos_T,
00186      *
00187      * the following example shows how to use setFilePos instead of fseek,
00188      * and getFilePos instead of ftell. The ANSI C fseek and ftell are not
00189      * 64 bit file I/O capable on most platforms. setFilePos and getFilePos
00190      * are defined as the corresponding POSIX fsetpos/fgetpos or
00191      * fsetpos64/fgetpos64 as required by your platform/OS in io64.h
00192      * These functions are 64 bit file I/O capable on all platforms.
00193      * Note that the offset parameter to setFilePos and getFilePos is
00194      * really a signed 64 bit int, int64_T, however, it MUST be cast to
00195      * an (fpos_T*).
00196      * fpos_T is defined as the appropriate fpos64_t or fpos_t as required
00197      * by your platform/OS in io64.h
00198      * Note that unlike fseek, setFilePos supports only absolute seeking
00199      * relative to the beginning of the file.
00200      */
00201 
00202     /* This note is only if you want to support relative seeking like
00203      * with fseek SEEK_CUR and SEEK_END. If you want to support relative
00204      * seeking, you should use getFileFstat as shown in the previous
00205      * example to obtain the file size.
00206      * This allows you to convert the relative offset you want to seek
00207      * to into an absolute offset which you can pass to setFilePos.
00208      */
00209 
00210     /* fp is the (FILE*) pointer to an already opened file.
00211      * offset is defined above. If the file existed already, this
00212      * will move the file pointer to the end of the file to prepare
00213      * for adding data at the end of the file.
00214      */
00215 
00216     mexPrintf("setFilePos() - ");
00217     if ( 0 == setFilePos( fp, (fpos_T*) &offset) )
00218     {
00219         mexPrintf("seek to zero-based byte offset %" FMT64 "d ok\n",offset);
00220     }
00221     else
00222     {
00223         mexfio64cleanup(fp,filename);
00224         mexErrMsgTxt("setFilePos() failed.");
00225     }
00226 
00227     mexPrintf("getFilePos() - ");
00228     if ( 0 == getFilePos( fp, (fpos_T*) &position ) )
00229     {
00230         mexPrintf("current zero-based byte offset is %" FMT64 "d\n",position);
00231     }
00232     else
00233     {
00234         mexfio64cleanup(fp,filename);
00235         mexErrMsgTxt("getFilePos() failed.");
00236     }
00237 
00238     /* fread() fwrite() fprintf() fscanf() and fclose() are used the
00239      * same way as before with no changes required to enable 64 bit
00240      * file I/O capability. Here a text string is written to the file
00241      * and then the file is closed.
00242      * If the file existed already, the string is appended at the end
00243      * of the file.
00244      */
00245 
00246     mexPrintf("fprintf() data: '%s'\n",mydata);
00247     fprintf(fp, "%s", mydata);
00248 
00249     /* get the current byte position of the file pointer and seek
00250      * to that position. This does not change the position of the file
00251      * pointer, but it updates the correct file size to be returned by
00252      * getFileFstat() below.
00253      */
00254 
00255     mexPrintf("getFilePos() - ");
00256     if ( 0 == getFilePos( fp, (fpos_T*) &position ) )
00257     {
00258         mexPrintf("current zero-based byte offset is %" FMT64 "d\n",position);
00259     }
00260     else
00261     {
00262         mexfio64cleanup(fp,filename);
00263         mexErrMsgTxt("getFilePos() failed.");
00264     }
00265 
00266     /* Before calling getFileFstat (which works on open files), you
00267      * should setFilePos to the current file position.
00268      * This does not move the file pointer, but it is necessary, as it
00269      * updates the file size in getFileFstat. This is necessary due to
00270      * the underlying C library implementation. If you call getFileFstat
00271      * on a file opened for writing, the file size may be incorrect
00272      * or 0 unless you call setFilePos before calling getFileFstat.
00273      * It does not matter to which position in the file you seek as long
00274      * as a seek is called before the fstat. Seeking to the current
00275      * position is only a suggestion.
00276      * Try commenting out the block of code with setFilePos() below
00277      * and then recompile and rerun this example at the MATLAB command
00278      * prompt to see that this causes the following getFileFstat() to not
00279      * show the updated file size after it was increased by the above
00280      * fprintf().
00281      */
00282 
00283     {
00284         mexPrintf("setFilePos() - ");
00285         if ( 0 == setFilePos( fp, (fpos_T*) &position) )
00286         {
00287             mexPrintf("seek to zero-based byte offset %" FMT64 "d ok\n",position);
00288         }
00289         else
00290         {
00291             mexfio64cleanup(fp,filename);
00292             mexErrMsgTxt("setFilePos() failed.");
00293         }
00294     }
00295 
00296     /* (8)  fileno(),
00297      * (9)  structStat,
00298      * (10) getFileFstat()
00299      *
00300      * In 32 bit file I/O, for files less than 2GB in size, one
00301      * technique that was sometimes used to obtain the size in bytes
00302      * of an already opened file was to use fseek() with the SEEK_END
00303      * parameter to seek to the end of the file, then call ftell() to
00304      * get the current position of the file pointer, and hence the size
00305      * of the file in bytes, and then fseek() back to the original
00306      * position.
00307      *
00308      * /// this is a technique of getting the file size of the
00309      * /// currently opened file in 32 bit file I/O
00310      * {
00311      *     FILE *fp;
00312      *     int current_position = 0;
00313      *     int file_size = 0;
00314      *     char *filename = "myfile";
00315      *
00316      *     fp = fopen(filename,"rb");
00317      *     current_position = ftell(fp); // save current position
00318      *     fseek(fp,0,SEEK_END); // seek to end of file
00319      *     file_size = ftell(fp); // get current position = file size
00320      *     fseek(fp,current_position,SEEK_SET); // seek to end of file
00321      *     printf("size of currently opened file is %d bytes\n",
00322      *         file_size);
00323      *     fclose(fp);
00324      * }
00325      *
00326      * Since fseek() is not supported for 64 bit file I/O on most
00327      * platforms, setFilePos() (the POSIX fsetpos()) will be used
00328      * instead, as it supports 64 bit file I/O on all platforms.
00329      * This function, however, supports only absolute seeking, the
00330      * equivalent of using fseek() with SEEK_SET, thus, you cannot
00331      * use the fseek() SEEK_END/ftell() technique to get the size of
00332      * an already opened file. Instead, you should use getFileFstat()
00333      * as shown below.
00334      * The following example shows how to use structStat, getFileFstat,
00335      * and fileno to get the size of an opened file in bytes, using the
00336      * opened file pointer.
00337      * structStat is defined in io64.h as the appropriate stat struct to
00338      * support large file I/O as required on your platform.
00339      * getFileFstat is defined in io64.h as the appropriate fstat
00340      * function as required on your platform.
00341      * fileno is defined in io64.h as required on your platform.
00342      * fp is the (FILE*) pointer to an already opened file
00343      */
00344 
00345     {
00346         structStat statbuf;
00347         int64_T fileSize = 0;
00348 
00349         mexPrintf("getFileFstat() - ");
00350         if ( 0 == getFileFstat(fileno(fp), &statbuf ) )
00351         {
00352             fileSize = statbuf.st_size;
00353             mexPrintf("file size is %" FMT64 "d bytes\n",fileSize);
00354         }
00355         else
00356         {
00357             mexfio64cleanup(fp,filename);
00358             mexErrMsgTxt("getFileFstat() failed.");
00359         }
00360     }
00361 
00362     /* close the file normally */
00363 
00364     mexPrintf("fclose()\n");
00365     fclose(fp);
00366 
00367     /* (11) getFileStat()
00368      *
00369      * the following example shows how to use getFileStat
00370      * to get the size of an unopened file in bytes, using the name of
00371      * the file on disk.
00372      * getFileStat is defined in io64.h as the appropriate stat
00373      * function as required on your platform.
00374      */
00375 
00376     {
00377         structStat statbuf;
00378         int64_T fileSize = 0;
00379 
00380         mexPrintf("getFileStat() - ");
00381         if ( 0 == getFileStat(filename, &statbuf) )
00382         {
00383             fileSize = statbuf.st_size;
00384             mexPrintf("file size is %" FMT64 "d bytes\n",fileSize);
00385         }
00386         else
00387         {
00388             mexfio64cleanup(fp,filename);
00389             mexErrMsgTxt("getFileStat() failed.");
00390         }
00391     }
00392 
00393     /* delete the file */
00394 
00395     mexPrintf("remove() - deleting file '%s'\n",filename);
00396     remove(filename);
00397 
00398     return;
00399 }

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy