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 }