001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.object; 016 017import java.io.File; 018import java.util.Enumeration; 019import java.util.Hashtable; 020import java.util.Iterator; 021import java.util.Map; 022import java.util.StringTokenizer; 023import java.util.Vector; 024 025 026/** 027 * FileFormat defines general interfaces for working with files whose data is 028 * organized according to a supported format. 029 * 030 * FileFormat is a pluggable component. New implementing classes of FileFormat 031 * can be added to the list of supported file formats. Current implementing 032 * classes include H5File and H4File. By default, H5File and H4File are added to 033 * the list of supported file formats maintained by the static FileFormat 034 * instance. 035 * 036 * <pre> 037 * FileFormat 038 * _________________|_________________ 039 * | | | 040 * H5File H4File Other... 041 * </pre> 042 * 043 * A FileFormat instance may exist without being associated with a given file. A 044 * FileFormat instance may be associated with a file that is not open for 045 * access. Most typically, a FileFormat instance is used to open the associated 046 * file and perform operations such as retrieval and manipulation (if the file 047 * access is read-write) of the file structure and objects. 048 * 049 * @author Peter X. Cao 050 * @version 2.4 9/4/2007 051 */ 052public abstract class FileFormat extends File { 053 private static final long serialVersionUID = -4700692313888420796L; 054 055 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FileFormat.class); 056 057 /*************************************************************************** 058 * File access flags used in calls to createInstance( String, flag ); 059 **************************************************************************/ 060 061 /** 062 * File first time access flag for open file. With this access flag, added 063 * to the regular value, indicates this file has no existing state. 064 * 065 */ 066 public static final int OPEN_NEW = 1; 067 068 /** 069 * File access flag for read-only permission. With this access flag, 070 * modifications to the file will not be allowed. 071 * 072 * @see #createInstance(String, int ) 073 */ 074 public static final int READ = 2; 075 076 /** 077 * File access flag for read/write permission. With this access flag, 078 * modifications to the file will be allowed. Behavior if the file does not 079 * exist or cannot be opened for read/write access depends on the 080 * implementing class. 081 * 082 * @see #createInstance(String, int) 083 */ 084 public static final int WRITE = 4; 085 086 /** 087 * File access flag for creating/truncating with read-write permission. If 088 * the file already exists, it will be truncated when opened. With this 089 * access flag, modifications to the file will be allowed. Behavior if file 090 * can't be created, or if it exists but can't be opened for read/write 091 * access, depends on the implementing class. 092 * 093 * @see #createInstance(String, int ) 094 */ 095 public static final int CREATE = 8; 096 097 /*************************************************************************** 098 * File creation flags used in calls to createFile( String, flag ); 099 **************************************************************************/ 100 101 /** 102 * Flag for creating/truncating a file. If the file already exists, it will 103 * be truncated when opened. If the file does not exist, it will be created. 104 * Modifications to the file will be allowed. 105 * 106 * @see #createFile(String, int ) 107 */ 108 public static final int FILE_CREATE_DELETE = 10; 109 110 /** 111 * Flag for creating/opening a file. If the file already exists, it will be 112 * opened without changing the existing contents. If the file does not 113 * exist, it will be created. Modifications to the file will be allowed. 114 * 115 * @see #createFile(String, int ) 116 */ 117 public static final int FILE_CREATE_OPEN = 20; 118 119 /** 120 * Flag to indicate if the earliest version of library is used when creating 121 * a new file. 122 * 123 * @see #createFile(String, int ) 124 */ 125 public static final int FILE_CREATE_EARLY_LIB = 40; 126 127 128 /*************************************************************************** 129 * Keys and fields related to supported file formats. 130 **************************************************************************/ 131 132 /** Key for HDF4 file format. */ 133 public static final String FILE_TYPE_HDF4 = "HDF4"; 134 135 /** Key for HDF5 file format. */ 136 public static final String FILE_TYPE_HDF5 = "HDF5"; 137 138 /** Key for NetCDF file format. */ 139 public static final String FILE_TYPE_NC3 = "NetCDF3"; 140 141 /** 142 * A separator that separates file name and object name. 143 * 144 * @see hdf.object.FileFormat#getHObject(String) 145 */ 146 public static final String FILE_OBJ_SEP = "://"; 147 148 /** 149 * FileList keeps a list of supported FileFormats. This list can be updated 150 * and queried at runtime. 151 * 152 * @see #addFileFormat(String,FileFormat) 153 * @see #getFileFormat(String) 154 * @see #getFileFormatKeys() 155 * @see #getFileFormats() 156 * @see #removeFileFormat(String) 157 */ 158 private static final Map<String, FileFormat> FileList = new Hashtable<>(10); 159 160 /** 161 * A list of file extensions for the supported file formats. This list of 162 * file extensions is not integrated with the supported file formats kept in 163 * FileList, but is provided as a convenience for applications who may 164 * choose to process only those files with recognized extensions. 165 */ 166 private static String extensions = "hdf, h4, hdf5, h5, nc, fits"; 167 168 /*************************************************************************** 169 * Sizing information and class metadata 170 **************************************************************************/ 171 172 /** 173 * Current Java applications, such as HDFView, cannot handle files with 174 * large numbers of objects due to JVM memory limitations. For example, 175 * 1,000,000 objects is too many. max_members is defined so that 176 * applications such as HDFView will load up to <i>max_members</i> objects 177 * starting with the <i>start_members</i> -th object. The implementing class 178 * has freedom in its interpretation of how to "count" objects in the file. 179 */ 180 private int max_members = 10000; // 10,000 by default 181 /** 182 * The start number for max_members . 183 */ 184 private int start_members = 0; // 0 by default 185 186 /** 187 * File identifier. -1 indicates the file is not open. 188 */ 189 protected long fid = -1; 190 191 /** 192 * The absolute pathname (path+name) of the file. 193 */ 194 protected String fullFileName = null; 195 196 /** 197 * Flag indicating if the file access is read-only. 198 */ 199 protected boolean isReadOnly = false; 200 201 /*************************************************************************** 202 * Class initialization method 203 **************************************************************************/ 204 205 /** 206 * By default, HDF4 and HDF5 file formats are added to the supported formats 207 * list. 208 */ 209 static { 210 // add HDF4 to default modules 211 if (FileFormat.getFileFormat(FILE_TYPE_HDF4) == null) { 212 try { 213 @SuppressWarnings("rawtypes") 214 Class fileclass = Class.forName("hdf.object.h4.H4File"); 215 FileFormat fileformat = (FileFormat) fileclass.newInstance(); 216 if (fileformat != null) { 217 FileFormat.addFileFormat(FILE_TYPE_HDF4, fileformat); 218 log.debug("FILE_TYPE_HDF4 file format added"); 219 } 220 } 221 catch (Exception err) { 222 log.debug("FILE_TYPE_HDF4 instance failure: ", err); 223 } 224 } 225 226 // add HDF5 to default modules 227 if (FileFormat.getFileFormat(FILE_TYPE_HDF5) == null) { 228 try { 229 @SuppressWarnings("rawtypes") 230 Class fileclass = Class.forName("hdf.object.h5.H5File"); 231 FileFormat fileformat = (FileFormat) fileclass.newInstance(); 232 if (fileformat != null) { 233 FileFormat.addFileFormat(FILE_TYPE_HDF5, fileformat); 234 log.debug("FILE_TYPE_HDF5 file format added"); 235 } 236 } 237 catch (Exception err) { 238 log.debug("FILE_TYPE_HDF5 instance failure: ", err); 239 } 240 } 241 242 // add NetCDF to default modules 243 if (FileFormat.getFileFormat(FILE_TYPE_NC3) == null) { 244 try { 245 @SuppressWarnings("rawtypes") 246 Class fileclass = Class.forName("hdf.object.nc2.NC2File"); 247 FileFormat fileformat = (FileFormat) fileclass.newInstance(); 248 if (fileformat != null) { 249 FileFormat.addFileFormat(FILE_TYPE_NC3, fileformat); 250 log.debug("NetCDF3 file format added"); 251 } 252 } 253 catch (Exception err) { 254 log.debug("NetCDF3 instance failure: ", err); 255 } 256 } 257 258 // add FITS to default modules 259 if (FileFormat.getFileFormat("FITS") == null) { 260 try { 261 @SuppressWarnings("rawtypes") 262 Class fileclass = Class.forName("hdf.object.fits.FitsFile"); 263 FileFormat fileformat = (FileFormat) fileclass.newInstance(); 264 if (fileformat != null) { 265 FileFormat.addFileFormat("FITS", fileformat); 266 log.debug("Fits file format added"); 267 } 268 } 269 catch (Exception err) { 270 log.debug("FITS instance failure: ", err); 271 } 272 } 273 274 } 275 276 /*************************************************************************** 277 * Constructor 278 **************************************************************************/ 279 280 /** 281 * Creates a new FileFormat instance with the given filename. 282 * 283 * The filename in this method call is equivalent to the pathname in the 284 * java.io.File class. The filename is converted into an abstract pathname 285 * by the File class. 286 * 287 * Typically this constructor is not called directly, but is called by a 288 * constructor of an implementing class. Applications most frequently use 289 * the <i>createFile()</i>, <i>createInstance()</i>, or <i>getInstance()</i> 290 * methods to generate a FileFormat instance with an associated filename. 291 * 292 * The file is not opened by this call. The read-only flag is set to false 293 * by this call. 294 * 295 * @param filename 296 * The filename; a pathname string. 297 * @throws NullPointerException 298 * If the <code>filename</code> argument is <code>null</code>. 299 * @see java.io.File#File(String) 300 * @see #createFile(String, int) 301 * @see #createInstance(String, int) 302 * @see #getInstance(String) 303 */ 304 public FileFormat(String filename) { 305 super(filename); 306 307 fullFileName = filename; 308 309 if ((filename != null) && (filename.length() > 0)) { 310 try { 311 fullFileName = this.getAbsolutePath(); 312 } 313 catch (Exception ex) { 314 log.debug("File {} getAbsolutePath failure: ", filename, ex); 315 } 316 } 317 isReadOnly = false; 318 log.trace("fullFileName={} isReadOnly={}", fullFileName, isReadOnly); 319 } 320 321 /*************************************************************************** 322 * Class methods 323 **************************************************************************/ 324 325 /** 326 * Adds a FileFormat with specified key to the list of supported formats. 327 * 328 * This method allows a new FileFormat, tagged with an identifying key, to 329 * be added dynamically to the list of supported File Formats. Using it, 330 * applications can add new File Formats at runtime. 331 * 332 * For example, to add a new File Format with the key "xyz" that is 333 * implemented by the class xyzFile in the package companyC.files, an 334 * application would make the following calls: 335 * 336 * <pre> 337 * Class fileClass = Class.forName( "companyC.files.xyzFile" ); 338 * FileFormat ff = (FileFormat) fileClass.newInstance(); 339 * if ( ff != null ) { 340 * ff.addFileFormat ("xyz", ff ) 341 * } 342 * </pre> 343 * 344 * If either <code>key</code> or <code>fileformat</code> are 345 * <code>null</code>, or if <code>key</code> is already in use, the method 346 * returns without updating the list of supported File Formats. 347 * 348 * @param key 349 * A string that identifies the FileFormat. 350 * @param fileformat 351 * An instance of the FileFormat to be added. 352 * @see #getFileFormat(String) 353 * @see #getFileFormatKeys() 354 * @see #getFileFormats() 355 * @see #removeFileFormat(String) 356 */ 357 public static final void addFileFormat(String key, FileFormat fileformat) { 358 if ((fileformat == null) || (key == null)) 359 return; 360 361 key = key.trim(); 362 363 if (!FileList.containsKey(key)) 364 FileList.put(key, fileformat); 365 } 366 367 /** 368 * Returns the FileFormat with specified key from the list of supported 369 * formats. 370 * 371 * This method returns a FileFormat instance, as identified by an 372 * identifying key, from the list of supported File Formats. 373 * 374 * If the specified key is in the list of supported formats, the instance of 375 * the associated FileFormat object is returned. If the specified key is not 376 * in the list of supported formats, <code>null</code> is returned. 377 * 378 * @param key 379 * A string that identifies the FileFormat. 380 * @return The FileFormat that matches the given key, or <code>null</code> 381 * if the key is not found in the list of supported File Formats. 382 * @see #addFileFormat(String,FileFormat) 383 * @see #getFileFormatKeys() 384 * @see #getFileFormats() 385 * @see #removeFileFormat(String) 386 */ 387 public static final FileFormat getFileFormat(String key) { 388 return FileList.get(key); 389 } 390 391 /** 392 * Returns an Enumeration of keys for all supported formats. 393 * 394 * This method returns an Enumeration containing the unique keys (Strings) 395 * for the all File Formats in the list of supported File Formats. 396 * 397 * @return An Enumeration of keys that are in the list of supported formats. 398 * @see #addFileFormat(String,FileFormat) 399 * @see #getFileFormat(String) 400 * @see #getFileFormats() 401 * @see #removeFileFormat(String) 402 */ 403 @SuppressWarnings("rawtypes") 404 public static final Enumeration getFileFormatKeys() { 405 return ((Hashtable) FileList).keys(); 406 } 407 408 /** 409 * Returns an array of supported FileFormat instances. 410 * 411 * This method returns an array of FileFormat instances that appear in the 412 * list of supported File Formats. 413 * 414 * If the list of supported formats is empty, <code>null</code> is returned. 415 * 416 * @return An array of all FileFormat instances in the list of supported 417 * File Formats, or <code>null</code> if the list is empty. 418 * @see #addFileFormat(String,FileFormat) 419 * @see #getFileFormat(String) 420 * @see #getFileFormatKeys() 421 * @see #removeFileFormat(String) 422 */ 423 @SuppressWarnings("rawtypes") 424 public static final FileFormat[] getFileFormats() { 425 int n = FileList.size(); 426 if (n <= 0) 427 return null; 428 429 int i = 0; 430 FileFormat[] fileformats = new FileFormat[n]; 431 Enumeration<?> local_enum = ((Hashtable) FileList).elements(); 432 while (local_enum.hasMoreElements()) 433 fileformats[i++] = (FileFormat) local_enum.nextElement(); 434 435 return fileformats; 436 } 437 438 /** 439 * Removes a FileFormat from the list of supported formats. 440 * 441 * This method removes a FileFormat, as identified by the specified key, 442 * from the list of supported File Formats. 443 * 444 * If the specified key is in the list of supported formats, the instance of 445 * the FileFormat object that is being removed from the list is returned. If 446 * the key is not in the list of supported formats, <code>null</code> is 447 * returned. 448 * 449 * @param key 450 * A string that identifies the FileFormat to be removed. 451 * @return The FileFormat that is removed, or <code>null</code> if the key 452 * is not found in the list of supported File Formats. 453 * @see #addFileFormat(String,FileFormat) 454 * @see #getFileFormat(String) 455 * @see #getFileFormatKeys() 456 * @see #getFileFormats() 457 */ 458 public static final FileFormat removeFileFormat(String key) { 459 return FileList.remove(key); 460 } 461 462 /** 463 * Adds file extension(s) to the list of file extensions for supported file 464 * formats. 465 * 466 * Multiple extensions can be included in the single parameter if they are 467 * separated by commas. 468 * 469 * The list of file extensions updated by this call is not linked with 470 * supported formats that implement FileFormat objects. The file extension 471 * list is maintained for the benefit of applications that may choose to 472 * recognize only those files with extensions that appear in the list of 473 * file extensions for supported file formats. 474 * 475 * By default, the file extensions list includes: "hdf, h4, hdf5, h5" 476 * 477 * @param extension 478 * The file extension(s) to add. 479 * @see #addFileFormat(String,FileFormat) 480 * @see #getFileExtensions() 481 */ 482 public static final void addFileExtension(String extension) { 483 if ((extensions == null) || (extensions.length() <= 0)) 484 extensions = extension; 485 486 StringTokenizer currentExt = new StringTokenizer(extensions, ","); 487 Vector<String> tokens = new Vector<>(currentExt.countTokens() + 5); 488 489 while (currentExt.hasMoreTokens()) 490 tokens.add(currentExt.nextToken().trim().toLowerCase()); 491 492 currentExt = new StringTokenizer(extension, ","); 493 String ext = null; 494 while (currentExt.hasMoreTokens()) { 495 ext = currentExt.nextToken().trim().toLowerCase(); 496 if (tokens.contains(ext)) 497 continue; 498 499 extensions = extensions + ", " + ext; 500 } 501 502 tokens.setSize(0); 503 } 504 505 /** 506 * Returns a list of file extensions for all supported file formats. 507 * 508 * The extensions in the returned String are separates by commas: 509 * "hdf, h4, hdf5, h5" 510 * 511 * It is the responsibility of the application to update the file extension 512 * list using {@link #addFileExtension(String)} when new FileFormat 513 * implementations are added. 514 * 515 * @return A list of file extensions for all supported file formats. 516 * @see #addFileExtension(String) 517 */ 518 public static final String getFileExtensions() { 519 return extensions; 520 } 521 522 /** 523 * Creates a FileFormat instance for the specified file. 524 * 525 * This method checks the list of supported file formats to find one that 526 * matches the format of the specified file. If a match is found, the method 527 * returns an instance of the associated FileFormat object. If no match is 528 * found, <code>null</code> is returned. 529 * 530 * For example, if "test_hdf5.h5" is an HDF5 file, 531 * FileFormat.getInstance("test_hdf5.h5") will return an instance of H5File. 532 * 533 * The file is not opened as part of this call. Read/write file access is 534 * associated with the FileFormat instance if the matching file format 535 * supports read/write access. Some file formats only support read access. 536 * 537 * @param filename 538 * A valid file name, with a relative or absolute path. 539 * @return An instance of the matched FileFormat; <code>null</code> if no 540 * match. 541 * @throws IllegalArgumentException 542 * If the <code>filename</code> argument is <code>null</code> or 543 * does not specify an existing file. 544 * @throws Exception 545 * If there are problems creating the new instance. 546 * @see #createFile(String, int) 547 * @see #createInstance(String, int) 548 * @see #getFileFormats() 549 */ 550 @SuppressWarnings("rawtypes") 551 public static final FileFormat getInstance(String filename) throws Exception { 552 if ((filename == null) || (filename.length() <= 0)) 553 throw new IllegalArgumentException("Invalid file name: " + filename); 554 555 if (!(new File(filename)).exists()) 556 throw new IllegalArgumentException("File " + filename + " does not exist."); 557 558 FileFormat fileFormat = null; 559 FileFormat knownFormat = null; 560 Enumeration<?> elms = ((Hashtable) FileList).elements(); 561 562 while (elms.hasMoreElements()) { 563 knownFormat = (FileFormat) elms.nextElement(); 564 if (knownFormat.isThisType(filename)) { 565 try { 566 fileFormat = knownFormat.createInstance(filename, WRITE); 567 } 568 catch (Exception ex) { 569 log.debug("File {} createInstance failure: ", filename, ex); 570 } 571 break; 572 } 573 } 574 575 return fileFormat; 576 } 577 578 /*************************************************************************** 579 * Implementation Class methods. These methods are related to the 580 * implementing FileFormat class, but not to a particular instance of that 581 * class. Since we can't override class methods (they can only be shadowed 582 * in Java), these are instance methods. 583 * 584 * The non-abstract methods just throw an exception indicating that the 585 * implementing class doesn't support the functionality. 586 **************************************************************************/ 587 588 /** 589 * Returns the version of the library for the implementing FileFormat class. 590 * 591 * The implementing FileFormat classes have freedom in how they obtain or 592 * generate the version number that is returned by this method. The H5File 593 * and H4File implementations query the underlying HDF libraries and return 594 * the reported version numbers. Other implementing classes may generate the 595 * version string directly within the called method. 596 * 597 * @return The library version. 598 */ 599 public abstract String getLibversion(); 600 601 /** 602 * Checks if the class implements the specified FileFormat. 603 * 604 * The Java "instanceof" operation is unable to check if an object is an 605 * instance of a FileFormat that is loaded at runtime. This method provides 606 * the "instanceof" functionality, and works for implementing classes that 607 * are loaded at runtime. 608 * 609 * This method lets applications that only access the abstract object layer 610 * determine the format of a given instance of the abstract class. 611 * 612 * For example, HDFView uses the following code to determine if a file is an 613 * HDF5 file: 614 * 615 * <pre> 616 * FileFormat h5F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 617 * HObject hObject = viewer.getTreeView().getCurrentObject(); 618 * FileFormat thisF = hObject.getFileFormat(); 619 * boolean isH5 = h5F.isThisType(thisF); 620 * </pre> 621 * 622 * @param fileFormat 623 * The FileFormat to be checked. 624 * @return True if this instance implements the specified FileFormat; 625 * otherwise returns false. 626 * @see #isThisType(String) 627 */ 628 public abstract boolean isThisType(FileFormat fileFormat); 629 630 /** 631 * Checks if the implementing FileFormat class matches the format of the 632 * specified file. 633 * 634 * For example, if "test.h5" is an HDF5 file, the first call to isThisType() 635 * in the code fragment shown will return <code>false</code>, and the second 636 * call will return <code>true</code>. 637 * 638 * <pre> 639 * FileFormat ncF = FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3); 640 * FileFormat h4F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4); 641 * FileFormat h5F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 642 * boolean isH4 = h4F.isThisType("test.h5"); // false 643 * boolean isH5 = h5F.isThisType("test.h5"); // true 644 * </pre> 645 * 646 * @param filename 647 * The name of the file to be checked. 648 * @return True if the format of the file matches the format of this 649 * instance; otherwise returns false. 650 * @see #isThisType(FileFormat) 651 */ 652 public abstract boolean isThisType(String filename); 653 654 /** 655 * Creates a file with the specified name and returns a new FileFormat 656 * implementation instance associated with the file. 657 * 658 * This method creates a file whose format is the same as that of the 659 * implementing class. An instance of the FileFormat implementing class is 660 * created and associated with the file. That instance is returned by the 661 * method. 662 * 663 * The filename in this method call is equivalent to the pathname in the 664 * java.io.File class. The filename is converted into an abstract pathname 665 * by the File class. 666 * 667 * A flag controls the behavior if the named file already exists. The flag 668 * values and corresponding behaviors are: 669 * <ul> 670 * <li>FILE_CREATE_DELETE: Create a new file or truncate an existing one. 671 * <li>FILE_CREATE_OPEN: Create a new file or open an existing one. 672 * </ul> 673 * 674 * If the flag is FILE_CREATE_DELETE, the method will create a new file or 675 * truncate an existing file. If the flag is FILE_CREATE_OPEN and the file 676 * does not exist, the method will create a new file. 677 * 678 * This method does not open the file for access, nor does it confirm that 679 * the file can later be opened read/write. The file open is carried out by 680 * the <i>open()</i> call. 681 * 682 * @param filename 683 * The filename; a pathname string. 684 * @param createFlag 685 * The creation flag, which determines behavior when the file 686 * already exists. Acceptable values are 687 * <code>FILE_CREATE_DELETE</code> and 688 * <code>FILE_CREATE_OPEN</code>. 689 * @throws NullPointerException 690 * If the <code>filename</code> argument is <code>null</code>. 691 * @throws UnsupportedOperationException 692 * If the implementing class does not support the file creation operation. 693 * @throws Exception 694 * If the file cannot be created or if the creation flag has an 695 * unexpected value. The exceptions thrown vary depending on the 696 * implementing class. 697 * @see #createInstance(String, int) 698 * @see #getInstance(String) 699 * @see #open() 700 * 701 * @return the FileFormat instance. 702 */ 703 public FileFormat createFile(String filename, int createFlag) throws Exception { 704 // If the implementing subclass doesn't have this method then that 705 // format doesn't support File Creation and we throw an exception. 706 throw new UnsupportedOperationException("FileFormat FileFormat.createFile(...) is not implemented."); 707 } 708 709 /** 710 * Creates a FileFormat implementation instance with specified filename and 711 * access. 712 * 713 * This method creates an instance of the FileFormat implementing class and 714 * sets the filename and file access parameters. 715 * 716 * The filename in this method call is equivalent to the pathname in the 717 * java.io.File class. The filename is converted into an abstract pathname 718 * by the File class. 719 * 720 * The access parameter values and corresponding behaviors at file open: 721 * <ul> 722 * <li>READ: Read-only access. Fail if file doesn't exist. 723 * <li>WRITE: Read/Write access. Behavior if file doesn't exist or can't be 724 * opened for read/write access depends on the implementing class. 725 * <li>CREATE: Read/Write access. Create a new file or truncate an existing 726 * one. Behavior if file can't be created, or if it exists but can't be 727 * opened read/write depends on the implementing class. 728 * </ul> 729 * 730 * Some FileFormat implementing classes may only support READ access and 731 * will use READ regardless of the value specified in the call. Refer to the 732 * implementing class documentation for details. 733 * 734 * This method does not open the file for access, nor does it confirm that 735 * the file can later be opened read/write or created. The file open is 736 * carried out by the <i>open()</i> call. 737 * 738 * Example (without exception handling): 739 * 740 * <pre> 741 * // Request the implementing class of FileFormat: H5File 742 * FileFormat h5file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 743 * 744 * // Create an instance of H5File object with read/write access 745 * H5File test1 = (H5File) h5file.createInstance("test_hdf5.h5", 746 * FileFormat.WRITE); 747 * 748 * // Open the file and load the file structure; file id is returned. 749 * int fid = test1.open(); 750 * </pre> 751 * 752 * @param filename 753 * The filename; a pathname string. 754 * @param access 755 * The file access flag, which determines behavior when file is 756 * opened. Acceptable values are <code> READ, WRITE, </code> and 757 * <code>CREATE</code>. 758 * @throws NullPointerException 759 * If the <code>filename</code> argument is <code>null</code>. 760 * @throws Exception 761 * If the instance cannot be created or if the access flag has 762 * an unexpected value. The exceptions thrown vary depending on 763 * the implementing class. 764 * @see #createFile(String, int) 765 * @see #getInstance(String) 766 * @see #open() 767 * 768 * @return the FileFormat instance. 769 */ 770 public abstract FileFormat createInstance(String filename, int access) throws Exception; 771 772 // REVIEW DOCS for createInstance() 773 // What if READ ONLY in implementation? What if file already open? 774 // Can we doc exceptions better or in implementation methods? 775 776 /*************************************************************************** 777 * Final instance methods 778 * 779 * Related to a given instance of the class, but at the FileFormat level, 780 * not at the implementing class level. 781 **************************************************************************/ 782 783 /** 784 * Returns the absolute path for the file. 785 * 786 * For example, "/samples/hdf5_test.h5". If there is no file associated with 787 * this FileFormat instance, <code>null</code> is returned. 788 * 789 * @return The full path (file path + file name) of the associated file, or 790 * <code>null</code> if there is no associated file. 791 */ 792 public final String getFilePath() { 793 return fullFileName; 794 } 795 796 /** 797 * Returns file identifier of open file associated with this instance. 798 * 799 * @return The file identifer, or -1 if there is no file open. 800 */ 801 public final long getFID() { 802 return fid; 803 } 804 805 /** 806 * Returns true if the file access is read-only. 807 * 808 * This method returns true if the file access is read-only. If the file 809 * access is read-write, or if there is no file associated with the 810 * FileFormat instance, false will be returned. 811 * 812 * Note that this method may return true even if the file is not open for 813 * access when the method is called. The file access is set by the 814 * <i>createFile()</i>, <i>createInstance()</i>, or <i>getInstance()</i> 815 * call, and the file is opened for access by the <i>open()</i> call. 816 * 817 * @return True if the file access is read-only, otherwise returns false. 818 * @see #createFile(String, int) 819 * @see #createInstance(String, int) 820 * @see #getInstance(String) 821 * @see #open() 822 */ 823 public final boolean isReadOnly() { 824 return isReadOnly; 825 } 826 827 /** 828 * Sets the maximum number of objects to be loaded into memory. 829 * 830 * Current Java applications, such as HDFView, cannot handle files with 831 * large numbers of objects due to JVM memory limitations. The maximum 832 * number limits the number of objects that will be loaded for a given 833 * FileFormat instance. 834 * 835 * The implementing FileFormat class has freedom in how it interprets the 836 * maximum number. H5File, for example, will load the maximum number of 837 * objects for each group in the file. 838 * 839 * @param n 840 * The maximum number of objects to be loaded into memory. 841 * @see #getMaxMembers() 842 * @see #setStartMembers(int) 843 */ 844 public final void setMaxMembers(int n) { 845 max_members = n; 846 } 847 848 /** 849 * Returns the maximum number of objects that can be loaded into memory. 850 * 851 * @return The maximum number of objects that can be loaded into memory. 852 * @see #setMaxMembers(int) 853 */ 854 public final int getMaxMembers() { 855 if (max_members<0) 856 return Integer.MAX_VALUE; // load the whole file 857 858 return max_members; 859 } 860 861 /** 862 * Sets the starting index of objects to be loaded into memory. 863 * 864 * The implementing FileFormat class has freedom in how it indexes objects 865 * in the file. 866 * 867 * @param idx 868 * The starting index of the object to be loaded into memory 869 * @see #getStartMembers() 870 * @see #setMaxMembers(int) 871 */ 872 public final void setStartMembers(int idx) { 873 start_members = idx; 874 } 875 876 /** 877 * Returns the index of the starting object to be loaded into memory. 878 * 879 * @return The index of the starting object to be loaded into memory. 880 * @see #setStartMembers(int) 881 */ 882 public final int getStartMembers() { 883 return start_members; 884 } 885 886 /** 887 * Returns the number of objects in memory. 888 * 889 * This method returns the total number of objects loaded into memory for 890 * this FileFormat instance. The method counts the objects that are loaded, 891 * which can take some time for a large number of objects. 892 * 893 * It is worth noting that the total number of objects in memory may be 894 * different than the total number of objects in the file. 895 * 896 * Since implementing classes have freedom in how they interpret and use the 897 * maximum number of members value, there may be differing numbers of 898 * objects in memory in different implementation instances, even with the 899 * same "use case". 900 * 901 * For example, say the use case is a file that contains 20,000 objects, the 902 * maximum number of members for an instance is 10,000, and the start member 903 * index is 1. There are 2 groups in the file. The root group contains 904 * 10,500 objects and the group "/g1" contains 9,500 objects. 905 * 906 * In an implementation that limits the total number of objects loaded to 907 * the maximum number of members, this method will return 10,000. 908 * 909 * In contrast, the H5File implementation loads up to the maximum number of 910 * members objects for each group in the file. So, with our use case 10,000 911 * objects will be loaded in the root group and 9,500 objects will be loaded 912 * into group "/g1". This method will return the value 19,500, which exceeds 913 * the maximum number of members value. 914 * 915 * @return The number of objects in memory. 916 * @see #getMaxMembers() 917 * @see #setMaxMembers(int) 918 * @see #getStartMembers() 919 * @see #setStartMembers(int) 920 */ 921 public final int getNumberOfMembers() { 922 HObject rootObject = getRootObject(); 923 924 // Account for root object 925 if (rootObject != null) 926 return ((Group) rootObject).depthFirstMemberList().size() + 1; 927 928 return 0; 929 } 930 931 /*************************************************************************** 932 * Abstract Instance methods 933 * 934 * These methods are related to the Implementing FileFormat class and to 935 * particular instances of objects with those classes. 936 **************************************************************************/ 937 938 /** 939 * Opens file and returns a file identifier. 940 * 941 * This method uses the <code>filename</code> and <code>access</code> 942 * parameters specified in the <i>createFile()</i>, <i>createInstance()</i>, 943 * or <i>getInstance()</i> call to open the file. It returns the file 944 * identifier if successful, or a negative value in case of failure. 945 * 946 * The method also loads the file structure and basic information (name, 947 * type) for data objects in the file into the FileFormat instance. It does 948 * not load the contents of any data object. 949 * 950 * The structure of the file is stored in a tree starting from the root 951 * object. 952 * 953 * @return File identifier if successful; otherwise -1. 954 * @throws Exception 955 * If the file cannot be opened. The exceptions thrown vary 956 * depending on the implementing class. 957 * @see #createFile(String, int) 958 * @see #createInstance(String, int) 959 * @see #getInstance(String) 960 * @see #getRootObject() 961 */ 962 public abstract long open() throws Exception; 963 964 /** 965 * Closes file associated with this instance. 966 * 967 * This method closes the file associated with this FileFormat instance, as 968 * well as all objects associated with the file. 969 * 970 * @throws Exception 971 * If the file or associated objects cannot be closed. The 972 * exceptions thrown vary depending on the implementing class. 973 * @see #open() 974 */ 975 public abstract void close() throws Exception; 976 977 // REVIEW DOCS for close() 978 // What if we try to close a file whose fid is -1? Does this set fid to -1? 979 // What if it's not open? What if no file? are structures & root object 980 // still loaded? 981 // Can we doc exceptions better or in implementation methods? 982 983 /** 984 * Returns the root object for the file associated with this instance. 985 * 986 * The root object is an HObject that represents the root group of a 987 * file. If the file has not yet been opened, or if there is no file 988 * associated with this instance, <code>null</code> will be returned. 989 * 990 * Starting from the root, applications can descend through the tree 991 * structure and navigate among the file's objects. In the tree structure, 992 * internal items represent non-empty groups. Leaf items represent datasets, 993 * named datatypes, or empty groups. 994 * 995 * @return The root object of the file, or <code>null</code> if there is no 996 * associated file or if the associated file has not yet been opened. 997 * @see #open() 998 */ 999 public abstract HObject getRootObject(); 1000 1001 /** 1002 * Gets the HObject with the specified path from the file. 1003 * 1004 * This method returns the specified object from the file associated with 1005 * this FileFormat instance. 1006 * 1007 * If the specified object is a group, groups and datasets that are members 1008 * of the group will be accessible via the returned HObject instance. The 1009 * exact contents of the returned HObject instance depends on whether or not 1010 * {@link #open()} was called previously for this file. 1011 * <ul> 1012 * <li>If the file was opened prior to this method call, the complete tree 1013 * of objects under the group will be accessible via the returned HObject 1014 * instance. 1015 * <li>If the file was not opened prior to this method call, only the 1016 * members immediately under the group will be accessible via the returned 1017 * HOBject instance. 1018 * </ul> 1019 * 1020 * The decision to have different behaviors was made to give users some 1021 * control over the "cost" of the method. In many cases, a user wants only 1022 * one level of a tree, and the performance penalty for loading the entire 1023 * hierarchy of objects in a large and complex file can be significant. In 1024 * the case where <i>open()</i> has already been called, the HObject 1025 * instances have already been created in memory and can be returned 1026 * quickly. If <i>open()</i> has not been called, this method creates the 1027 * HObject instances before returning the requested HObject. 1028 * 1029 * For example, say we have the following structure in our file: 1030 * 1031 * <pre> 1032 * /g0 Group 1033 * /g0/dataset_comp Dataset {50, 10} 1034 * /g0/dataset_int Dataset {50, 10} 1035 * /g0/g00 Group 1036 * /g0/g00/dataset_float Dataset {50, 10} 1037 * /g0/g01 Group 1038 * /g0/g01/dataset_string Dataset {50, 10} 1039 * </pre> 1040 * 1041 * <ul> 1042 * <li>If <i>open()</i> is called before <i>get()</i>, the full structure of 1043 * file is loaded into memory. The call <code>get("/g0")</code> returns the 1044 * instance for /g0 with the information necessary to access 1045 * /g0/dataset_comp, /g0/dataset_int, /g0/g00, /g0/g00/dataset_float, 1046 * /g0/g01, and /g0/g01/dataset_string. 1047 * <li>If <i>open()</i> is not called before <i>get()</i>, only the objects 1048 * immediately under the specified group are accessible via the returned 1049 * HObject instance. In this example, the call <code>get("/go")</code> 1050 * returns the instance for /g0 with the information necessary to access 1051 * /g0/dataset_comp, /g0/dataset_int, /g0/g00, and /g0/g01. 1052 * </ul> 1053 * 1054 * @param path 1055 * Full path of the data object to be returned. 1056 * @return The object if it exists in the file; otherwise <code>null</code>. 1057 * @throws Exception 1058 * If there are unexpected problems in trying to retrieve the 1059 * object. The exceptions thrown vary depending on the 1060 * implementing class. 1061 */ 1062 public abstract HObject get(String path) throws Exception; 1063 1064 // REVIEW DOCS for get(); What if no file associated w/ instance? 1065 // Look at exceptions. Confirm example. Make sure perf tradeoffs 1066 // documented properly. 1067 1068 /** 1069 * Creates a named datatype in a file. 1070 * 1071 * The following code creates a named datatype in a file. 1072 * 1073 * <pre> 1074 * H5File file = (H5File) h5file.createInstance("test_hdf5.h5", FileFormat.WRITE); 1075 * H5Datatype dtype = file.createNamedDatatype( 1076 * nativetype, 1077 * "Native Integer"); 1078 * </pre> 1079 * @param tnative 1080 * the native datatype of the new datatype 1081 * @param name 1082 * name of the datatype to create, e.g. "Native Integer". 1083 * @return The new datatype if successful; otherwise returns null. 1084 * @throws Exception 1085 * The exceptions thrown vary depending on the implementing class. 1086 */ 1087 public Datatype createNamedDatatype(Datatype tnative, String name) throws Exception { 1088 // If the implementing subclass doesn't have this method then that 1089 // format doesn't support Named Datatypes and we throw an exception. 1090 throw new UnsupportedOperationException("Datatype FileFormat.createNamedDatatype(...) is not implemented."); 1091 } 1092 1093 // REVIEW DOCS for createDatatype(). Check and document exceptions. 1094 1095 /*************************************************************************** 1096 * Methods related to Datatypes and HObjects in the implementing FileFormat. 1097 * 1098 * Strictly speaking, these methods aren't related to FileFormat and the 1099 * actions could be carried out through the HObject and Datatype classes. 1100 * But, in some cases they allow a null input and expect the generated 1101 * object to be of a type that has particular FileFormat. Therefore, we put 1102 * them in the implementing FileFormat class so that we create the proper 1103 * type of HObject... H5Group or H4Group for example. 1104 * 1105 * Here again, if there could be Implementation Class methods we'd use 1106 * those. But, since we can't override class methods (they can only be 1107 * shadowed in Java), these are instance methods. 1108 * 1109 * The non-abstract methods just throw an exception indicating that the 1110 * implementing class doesn't support the functionality. 1111 **************************************************************************/ 1112 1113 /** 1114 * Creates a new datatype in memory. 1115 * 1116 * The following code creates an instance of H5Datatype in memory. 1117 * 1118 * <pre> 1119 * H5File file = (H5File) h5file.createInstance("test_hdf5.h5", FileFormat.WRITE); 1120 * H5Datatype dtype = file.createDatatype( 1121 * Datatype.CLASS_INTEGER, 1122 * 4, 1123 * Datatype.NATIVE, 1124 * Datatype.NATIVE); 1125 * </pre> 1126 * 1127 * @param tclass 1128 * class of datatype, e.g. Datatype.CLASS_INTEGER 1129 * @param tsize 1130 * size of the datatype in bytes, e.g. 4 for 32-bit integer. 1131 * @param torder 1132 * order of the byte endian, e.g. Datatype.ORDER_LE. 1133 * @param tsign 1134 * signed or unsigned of an integer, e.g. Datatype.SIGN_NONE. 1135 * @return The new datatype object if successful; otherwise returns null. 1136 * @throws Exception 1137 * The exceptions thrown vary depending on the implementing 1138 * class. 1139 */ 1140 public abstract Datatype createDatatype(int tclass, int tsize, int torder, int tsign) throws Exception; 1141 1142 /** 1143 * Creates a new datatype in memory. 1144 * 1145 * The following code creates an instance of H5Datatype in memory. 1146 * 1147 * <pre> 1148 * H5File file = (H5File) h5file.createInstance("test_hdf5.h5", FileFormat.WRITE); 1149 * H5Datatype dtype = file.createDatatype( 1150 * Datatype.CLASS_INTEGER, 1151 * 4, 1152 * Datatype.NATIVE, 1153 * Datatype.NATIVE, 1154 * basetype); 1155 * </pre> 1156 * 1157 * @param tclass 1158 * class of datatype, e.g. Datatype.CLASS_INTEGER 1159 * @param tsize 1160 * size of the datatype in bytes, e.g. 4 for 32-bit integer. 1161 * @param torder 1162 * order of the byte endian, e.g. Datatype.ORDER_LE. 1163 * @param tsign 1164 * signed or unsigned of an integer, e.g. Datatype.SIGN_NONE. 1165 * @param tbase 1166 * the base datatype of the new datatype 1167 * @return The new datatype object if successful; otherwise returns null. 1168 * @throws Exception 1169 * The exceptions thrown vary depending on the implementing 1170 * class. 1171 */ 1172 public Datatype createDatatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception { 1173 // Derived classes must override this function to use base type option 1174 return createDatatype(tclass, tsize, torder, tsign); 1175 } 1176 1177 // REVIEW DOCS for createDatatype(). Check and document exceptions. 1178 1179 /** 1180 * Creates a new dataset in a file with/without chunking/compression. 1181 * 1182 * The following example creates a 2D integer dataset of size 100X50 at the root group in an HDF5 1183 * file. 1184 * 1185 * <pre> 1186 * String name = "2D integer"; 1187 * Group pgroup = (Group) getRootObject(); 1188 * Datatype dtype = new H5Datatype(Datatype.CLASS_INTEGER, // class 1189 * 4, // size in bytes 1190 * Datatype.ORDER_LE, // byte order 1191 * Datatype.SIGN_NONE); // unsigned 1192 * long[] dims = { 100, 50 }; 1193 * long[] maxdims = dims; 1194 * long[] chunks = null; // no 1195 * // chunking 1196 * int gzip = 0; // no compression 1197 * Object data = null; // no initial data values 1198 * Dataset d = (H5File) file.createScalarDS(name, pgroup, dtype, dims, maxdims, chunks, gzip, data); 1199 * </pre> 1200 * 1201 * @param name 1202 * name of the new dataset, e.g. "2D integer" 1203 * @param pgroup 1204 * parent group where the new dataset is created. 1205 * @param type 1206 * datatype of the new dataset. 1207 * @param dims 1208 * dimension sizes of the new dataset, e.g. long[] dims = {100, 50}. 1209 * @param maxdims 1210 * maximum dimension sizes of the new dataset, null if maxdims is the same as dims. 1211 * @param chunks 1212 * chunk sizes of the new dataset, null if no chunking. 1213 * @param gzip 1214 * GZIP compression level (1 to 9), 0 or negative values if no compression. 1215 * @param fillValue 1216 * default value. 1217 * @param data 1218 * data written to the new dataset, null if no data is written to the new dataset. 1219 * 1220 * @return The new dataset if successful; otherwise returns null 1221 * @throws Exception 1222 * The exceptions thrown vary depending on the implementing class. 1223 */ 1224 public abstract Dataset createScalarDS(String name, Group pgroup, Datatype type, 1225 long[] dims, long[] maxdims, long[] chunks, 1226 int gzip, Object fillValue, Object data) throws Exception; 1227 1228 /** 1229 * Creates a new dataset in a file with/without chunking/compression. 1230 * 1231 * @param name 1232 * name of the new dataset, e.g. "2D integer" 1233 * @param pgroup 1234 * parent group where the new dataset is created. 1235 * @param type 1236 * datatype of the new dataset. 1237 * @param dims 1238 * dimension sizes of the new dataset, e.g. long[] dims = {100, 50}. 1239 * @param maxdims 1240 * maximum dimension sizes of the new dataset, null if maxdims is the same as dims. 1241 * @param chunks 1242 * chunk sizes of the new dataset, null if no chunking. 1243 * @param gzip 1244 * GZIP compression level (1 to 9), 0 or negative values if no compression. 1245 * @param data 1246 * data written to the new dataset, null if no data is written to the new dataset. 1247 * 1248 * @return The new dataset if successful; otherwise returns null 1249 * @throws Exception 1250 * The exceptions thrown vary depending on the implementing class. 1251 */ 1252 public Dataset createScalarDS(String name, Group pgroup, Datatype type, 1253 long[] dims, long[] maxdims, long[] chunks, 1254 int gzip, Object data) throws Exception { 1255 return createScalarDS(name, pgroup, type, dims, maxdims, chunks, gzip, null, data); 1256 } 1257 1258 // REVIEW DOCS for createScalarDS(). Check and document exceptions. 1259 1260 /** 1261 * Creates a new compound dataset in a file with/without chunking and 1262 * compression. 1263 * 1264 * The following example creates a compressed 2D compound dataset with size 1265 * of 100X50 in a root group. The compound dataset has two members, x and y. 1266 * Member x is an interger, member y is an 1-D float array of size 10. 1267 * 1268 * <pre> 1269 * String name = "2D compound"; 1270 * Group pgroup = (Group) getRootObject(); 1271 * long[] dims = {100, 50}; 1272 * long[] chunks = {1, 50}; 1273 * int gzip = 9; 1274 * String[] memberNames = {"x", "y"}; 1275 * 1276 * Datatype[] memberDatatypes = { 1277 * new H5Datatype(Datatype.CLASS_INTEGER, Datatype.NATIVE, 1278 * Datatype.NATIVE, Datatype.NATIVE) 1279 * new H5Datatype(Datatype.CLASS_FLOAT, Datatype.NATIVE, 1280 * Datatype.NATIVE, Datatype.NATIVE)); 1281 * 1282 * int[] memberSizes = {1, 10}; 1283 * Object data = null; // no initial data values 1284 * Dataset d = (H5File)file.createCompoundDS(name, pgroup, dims, null, 1285 * chunks, gzip, memberNames, memberDatatypes, memberSizes, null); 1286 * </pre> 1287 * 1288 * @param name 1289 * name of the new dataset 1290 * @param pgroup 1291 * parent group where the new dataset is created. 1292 * @param dims 1293 * dimension sizes of the new dataset. 1294 * @param maxdims 1295 * maximum dimension sizes of the new dataset, null if maxdims is 1296 * the same as dims. 1297 * @param chunks 1298 * chunk sizes of the new dataset, null if no chunking. 1299 * @param gzip 1300 * GZIP compression level (1 to 9), 0 or negative values if no 1301 * compression. 1302 * @param memberNames 1303 * names of the members. 1304 * @param memberDatatypes 1305 * datatypes of the members. 1306 * @param memberSizes 1307 * array sizes of the members. 1308 * @param data 1309 * data written to the new dataset, null if no data is written to 1310 * the new dataset. 1311 * 1312 * @return new dataset object if successful; otherwise returns null 1313 * @throws UnsupportedOperationException 1314 * If the implementing class does not support compound datasets. 1315 * @throws Exception 1316 * The exceptions thrown vary depending on the implementing 1317 * class. 1318 */ 1319 public Dataset createCompoundDS(String name, Group pgroup, 1320 long[] dims, long[] maxdims, long[] chunks, 1321 int gzip, String[] memberNames, Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception { 1322 // If the implementing subclass doesn't have this method then that 1323 // format doesn't support Compound DataSets and we throw an 1324 // exception. 1325 throw new UnsupportedOperationException("Dataset FileFormat.createCompoundDS(...) is not implemented."); 1326 } 1327 1328 /** 1329 * Creates a new image in a file. 1330 * 1331 * The following example creates a 2D image of size 100X50 in a root group. 1332 * 1333 * <pre> 1334 * String name = "2D image"; 1335 * Group pgroup = (Group) getRootObject(); 1336 * Datatype dtype = new H5Datatype(Datatype.CLASS_INTEGER, 1, Datatype.NATIVE, Datatype.SIGN_NONE); 1337 * long[] dims = {100, 50}; 1338 * long[] maxdims = dims; 1339 * long[] chunks = null; // no chunking 1340 * int gzip = 0; // no compression 1341 * int ncomp = 3; // RGB true color image 1342 * int interlace = ScalarDS.INTERLACE_PIXEL; 1343 * Object data = null; // no initial data values 1344 * Dataset d = (H5File) file.createScalarDS(name, pgroup, dtype, dims, maxdims, chunks, gzip, ncomp, interlace, data); 1345 * </pre> 1346 * 1347 * @param name 1348 * name of the new image, "2D image". 1349 * @param pgroup 1350 * parent group where the new image is created. 1351 * @param type 1352 * datatype of the new image. 1353 * @param dims 1354 * dimension sizes of the new dataset, e.g. long[] dims = {100, 1355 * 50}. 1356 * @param maxdims 1357 * maximum dimension sizes of the new dataset, null if maxdims is 1358 * the same as dims. 1359 * @param chunks 1360 * chunk sizes of the new dataset, null if no chunking. 1361 * @param gzip 1362 * GZIP compression level (1 to 9), 0 or negative values if no 1363 * compression. 1364 * @param ncomp 1365 * number of components of the new image, e.g. int ncomp = 3; // 1366 * RGB true color image. 1367 * @param interlace 1368 * interlace mode of the image. Valid values are 1369 * ScalarDS.INTERLACE_PIXEL, ScalarDS.INTERLACE_PLANEL and 1370 * ScalarDS.INTERLACE_LINE. 1371 * @param data 1372 * data value of the image, null if no data. 1373 * 1374 * @return The new image object if successful; otherwise returns null 1375 * 1376 * @throws Exception 1377 * The exceptions thrown vary depending on the implementing 1378 * class. 1379 */ 1380 public abstract Dataset createImage(String name, Group pgroup, Datatype type, 1381 long[] dims, long[] maxdims, long[] chunks, 1382 int gzip, int ncomp, int interlace, Object data) throws Exception; 1383 1384 // REVIEW DOCS for createImage(). Check and document exceptions. 1385 1386 /** 1387 * Creates a new group with specified name in existing group. 1388 * 1389 * If the parent group is null, the new group will be created in the root 1390 * group. 1391 * 1392 * @param name 1393 * The name of the new group. 1394 * @param parentGroup 1395 * The parent group, or null. 1396 * 1397 * @return The new group if successful; otherwise returns null. 1398 * 1399 * @throws Exception 1400 * The exceptions thrown vary depending on the implementing 1401 * class. 1402 */ 1403 public abstract Group createGroup(String name, Group parentGroup) throws Exception; 1404 1405 // REVIEW DOCS for createLink(). 1406 // Verify Implementing classes document these and also 1407 // 'do the right thing' if fid is -1, currentObj is non-null, if 1408 // object is null, or the root group then what? document & verify! 1409 1410 /** 1411 * Creates a soft, hard or external link to an existing object in the open file. 1412 * 1413 * If parentGroup is null, the new link is created in the root group. 1414 * 1415 * @param parentGroup 1416 * The group where the link is created. 1417 * @param name 1418 * The name of the link. 1419 * @param currentObj 1420 * The existing object the new link will reference. 1421 * @param type 1422 * The type of link to be created. It can be a hard link, a soft 1423 * link or an external link. 1424 * 1425 * @return The object pointed to by the new link if successful; otherwise 1426 * returns null. 1427 * 1428 * @throws Exception 1429 * The exceptions thrown vary depending on the implementing class. 1430 */ 1431 public HObject createLink(Group parentGroup, String name, HObject currentObj, int type) throws Exception { 1432 return createLink(parentGroup, name, currentObj); 1433 } 1434 1435 /** 1436 * Creates a soft or external link to an object in a file that does not exist 1437 * at the time the link is created. 1438 * 1439 * @param parentGroup 1440 * The group where the link is created. 1441 * @param name 1442 * The name of the link. 1443 * @param currentObj 1444 * The name of the object the new link will reference. The object 1445 * doesn't have to exist. 1446 * @param type 1447 * The type of link to be created. 1448 * 1449 * @return The H5Link object pointed to by the new link if successful; 1450 * otherwise returns null. 1451 * 1452 * @throws Exception 1453 * The exceptions thrown vary depending on the implementing class. 1454 */ 1455 public HObject createLink(Group parentGroup, String name, String currentObj, int type) throws Exception { 1456 return createLink(parentGroup, name, currentObj); 1457 } 1458 1459 /** 1460 * Copies the source object to a new destination. 1461 * 1462 * This method copies the source object to a destination group, and assigns 1463 * the specified name to the new object. 1464 * 1465 * The copy may take place within a single file or across files. If the source 1466 * object and destination group are in different files, the files must have 1467 * the same file format (both HDF5 for example). 1468 * 1469 * The source object can be a group, a dataset, or a named datatype. This 1470 * method copies the object along with all of its attributes and other 1471 * properties. If the source object is a group, this method also copies all 1472 * objects and sub-groups below the group. 1473 * 1474 * The following example shows how to use the copy method to create two 1475 * copies of an existing HDF5 file structure in a new HDF5 file. One copy 1476 * will be under /copy1 and the other under /copy2 in the new file. 1477 * 1478 * <pre> 1479 * // Open the existing file with the source object. 1480 * H5File existingFile = new H5File("existingFile.h5", FileFormat.READ); 1481 * existingFile.open(); 1482 * // Our source object will be the root group. 1483 * HObject srcObj = existingFile.get("/"); 1484 * // Create a new file. 1485 * H5File newFile = new H5File("newFile.h5", FileFormat.CREATE); 1486 * newFile.open(); 1487 * // Both copies in the new file will have the root group as their 1488 * // destination group. 1489 * Group dstGroup = (Group) newFile.get("/"); 1490 * // First copy goes to "/copy1" and second goes to "/copy2". 1491 * // Notice that we can use either H5File instance to perform the copy. 1492 * HObject copy1 = existingFile.copy(srcObj, dstGroup, "copy1"); 1493 * HObject copy2 = newFile.copy(srcObj, dstGroup, "copy2"); 1494 * // Close both the files. 1495 * file.close(); 1496 * newFile.close(); 1497 * </pre> 1498 * 1499 * @param srcObj 1500 * The object to copy. 1501 * @param dstGroup 1502 * The destination group for the new object. 1503 * @param dstName 1504 * The name of the new object. If dstName is null, the name of 1505 * srcObj will be used. 1506 * 1507 * @return The new object, or null if the copy fails. 1508 * 1509 * @throws Exception 1510 * are specific to the implementing class. 1511 */ 1512 public abstract HObject copy(HObject srcObj, Group dstGroup, String dstName) throws Exception; 1513 1514 /** 1515 * Deletes an object from a file. 1516 * 1517 * @param obj 1518 * The object to delete. 1519 * @throws Exception 1520 * The exceptions thrown vary depending on the implementing class. 1521 */ 1522 public abstract void delete(HObject obj) throws Exception; 1523 1524 // REVIEW DOCS for delete(). Check and document exceptions. 1525 1526 /** 1527 * Attaches a given attribute to an object. 1528 * 1529 * If an HDF(4&5) attribute exists in file, the method updates its value. If 1530 * the attribute does not exist in file, it creates the attribute in file 1531 * and attaches it to the object. It will fail to write a new attribute to 1532 * the object where an attribute with the same name already exists. To 1533 * update the value of an existing attribute in file, one needs to get the 1534 * instance of the attribute by getMetadata(), change its values, and use 1535 * writeAttribute() to write the value. 1536 * 1537 * @param obj 1538 * The object to which the attribute is attached to. 1539 * @param attr 1540 * The atribute to attach. 1541 * @param attrExisted 1542 * The indicator if the given attribute exists. 1543 * 1544 * @throws Exception 1545 * The exceptions thrown vary depending on the implementing class. 1546 */ 1547 public abstract void writeAttribute(HObject obj, Attribute attr, boolean attrExisted) throws Exception; 1548 1549 // REVIEW DOCS for writeAttribute(). Check and document exceptions. 1550 1551 /*************************************************************************** 1552 * Deprecated methods. 1553 **************************************************************************/ 1554 1555 /** 1556 * @deprecated As of 2.4, replaced by {@link #createFile(String, int)} 1557 * 1558 * The replacement method has an additional parameter that 1559 * controls the behavior if the file already exists. Use 1560 * <code>FileFormat.FILE_CREATE_DELETE</code> as the second 1561 * argument in the replacement method to mimic the behavior 1562 * originally provided by this method. 1563 * 1564 * @param fileName 1565 * The filename; a pathname string. 1566 * 1567 * @return the created file object 1568 * 1569 * @throws Exception if file cannot be created 1570 */ 1571 @Deprecated 1572 public final FileFormat create(String fileName) throws Exception { 1573 return createFile(fileName, FileFormat.FILE_CREATE_DELETE); 1574 } 1575 1576 /** 1577 * @deprecated As of 2.4, replaced by {@link #createInstance(String, int)} 1578 * 1579 * The replacement method has identical functionality and a more 1580 * descriptive name. Since <i>open</i> is used elsewhere to 1581 * perform a different function this method has been deprecated. 1582 * 1583 * @param pathname 1584 * The pathname string. 1585 * @param access 1586 * The file access properties 1587 * 1588 * @return the opened file object 1589 * 1590 * @throws Exception if the file cannot be opened 1591 */ 1592 @Deprecated 1593 public final FileFormat open(String pathname, int access) throws Exception { 1594 return createInstance(pathname, access); 1595 } 1596 1597 /** 1598 * @deprecated As of 2.4, replaced by 1599 * {@link #createCompoundDS(String, Group, long[], long[], long[], int, String[], Datatype[], int[], Object)} 1600 * 1601 * The replacement method has additional parameters: 1602 * <code>maxdims, chunks,</code> and <code>gzip</code>. To mimic 1603 * the behavior originally provided by this method, call the 1604 * replacement method with the following parameter list: 1605 * <code> ( name, pgroup, dims, null, null, -1, 1606 * memberNames, memberDatatypes, memberSizes, data ); </code> 1607 * 1608 * @param name 1609 * The dataset name. 1610 * @param pgroup 1611 * The dataset parent. 1612 * @param dims 1613 * The dataset dimensions. 1614 * @param memberNames 1615 * The dataset compound member names. 1616 * @param memberDatatypes 1617 * The dataset compound member datatypes. 1618 * @param memberSizes 1619 * The dataset compound member sizes. 1620 * @param data 1621 * The dataset data. 1622 * 1623 * @return 1624 * The dataset created. 1625 * 1626 * @throws Exception if the dataset cannot be created 1627 */ 1628 @Deprecated 1629 public final Dataset createCompoundDS(String name, Group pgroup, long[] dims, 1630 String[] memberNames, Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception { 1631 return createCompoundDS(name, pgroup, dims, null, null, -1, memberNames, memberDatatypes, memberSizes, data); 1632 } 1633 1634 /** 1635 * @deprecated As of 2.4, replaced by {@link #copy(HObject, Group, String)} 1636 * 1637 * To mimic the behavior originally provided by this method, 1638 * call the replacement method with <code>null</code> as the 3rd parameter. 1639 * 1640 * @param srcObj 1641 * The object to be copied 1642 * @param dstGroup 1643 * The group to contain the copied object 1644 * 1645 * @return the copied object 1646 * 1647 * @throws Exception if object can not be copied 1648 */ 1649 @Deprecated 1650 public final HObject copy(HObject srcObj, Group dstGroup) throws Exception { 1651 return copy(srcObj, dstGroup, null); 1652 } 1653 1654 /** 1655 * @deprecated As of 2.4, replaced by {@link #get(String)} 1656 * 1657 * This static method, which as been deprecated, causes two problems: 1658 * <ul> 1659 * <li>It can be very expensive if it is called many times or in 1660 * a loop because each call to the method creates an instance of a file. 1661 * <li>Since the method does not return the instance of the 1662 * file, the file cannot be closed directly and may be left open 1663 * (memory leak). The only way to close the file is through the 1664 * object returned by this method. 1665 * </ul> 1666 * 1667 * @param fullPath 1668 * The file path string. 1669 * 1670 * @return the object that has the given full path 1671 * 1672 * @throws Exception if the object can not be found 1673 */ 1674 @Deprecated 1675 public static final HObject getHObject(String fullPath) throws Exception { 1676 if ((fullPath == null) || (fullPath.length() <= 0)) 1677 return null; 1678 1679 String filename = null, path = null; 1680 int idx = fullPath.indexOf(FILE_OBJ_SEP); 1681 1682 if (idx > 0) { 1683 filename = fullPath.substring(0, idx); 1684 path = fullPath.substring(idx + FILE_OBJ_SEP.length()); 1685 if ((path == null) || (path.length() == 0)) 1686 path = "/"; 1687 } 1688 else { 1689 filename = fullPath; 1690 path = "/"; 1691 } 1692 1693 return FileFormat.getHObject(filename, path); 1694 }; 1695 1696 /** 1697 * @deprecated As of 2.4, replaced by {@link #get(String)} 1698 * 1699 * This static method, which as been deprecated, causes two problems: 1700 * <ul> 1701 * <li>It can be very expensive if it is called many times or in 1702 * a loop because each call to the method creates an instance of 1703 * a file. 1704 * <li>Since the method does not return the instance of the 1705 * file, the file cannot be closed directly and may be left open 1706 * (memory leak). The only way to close the file is through the 1707 * object returned by this method, for example: 1708 * <pre> 1709 * Dataset dset = H5File.getObject("hdf5_test.h5", "/images/iceburg"); 1710 * ... 1711 * // close the file through dset 1712 * dset.getFileFormat().close(); 1713 * </pre> 1714 * 1715 * </li> 1716 * </ul> 1717 * 1718 * @param filename 1719 * The filename string. 1720 * @param path 1721 * The path of the file 1722 * 1723 * @return the object that has the given filename and path returns null 1724 * 1725 * @throws Exception if the object can not be found 1726 */ 1727 @Deprecated 1728 public static final HObject getHObject(String filename, String path) throws Exception { 1729 if ((filename == null) || (filename.length() <= 0)) 1730 throw new IllegalArgumentException("Invalid file name. " + filename); 1731 1732 if (!(new File(filename)).exists()) 1733 throw new IllegalArgumentException("File does not exists"); 1734 1735 HObject obj = null; 1736 FileFormat file = FileFormat.getInstance(filename); 1737 1738 if (file != null) { 1739 obj = file.get(path); 1740 if (obj == null) 1741 file.close(); 1742 } 1743 1744 return obj; 1745 } 1746 1747 /** 1748 * Finds an object by its object ID 1749 * 1750 * @param file 1751 * the file containing the object 1752 * @param oid 1753 * the oid to search for 1754 * 1755 * @return the object that has the given OID; otherwise returns null 1756 */ 1757 public static final HObject findObject(FileFormat file, long[] oid) { 1758 if ((file == null) || (oid == null)) { 1759 log.debug("findObject(): file is null or oid is null"); 1760 return null; 1761 } 1762 1763 HObject theObj = null; 1764 1765 HObject theRoot = file.getRootObject(); 1766 if (theRoot == null) { 1767 log.debug("findObject(): rootObject is null"); 1768 return null; 1769 } 1770 1771 Iterator<HObject> member_it = ((Group) theRoot).breadthFirstMemberList().iterator(); 1772 while (member_it.hasNext()) { 1773 theObj = member_it.next(); 1774 if (theObj.equalsOID(oid)) 1775 break; 1776 } 1777 1778 return theObj; 1779 } 1780 1781 /** 1782 * Finds an object by the full path of the object (path+name) 1783 * 1784 * @param file 1785 * the file containing the object 1786 * @param path 1787 * the full path of the object to search for 1788 * 1789 * @return the object that has the given path; otherwise returns null 1790 */ 1791 public static final HObject findObject(FileFormat file, String path) { 1792 log.trace("findObject({}): start", path); 1793 1794 if ((file == null) || (path == null)) { 1795 log.debug("findObject(): file is null or path is null"); 1796 return null; 1797 } 1798 1799 if (!path.endsWith("/")) 1800 path = path + "/"; 1801 1802 HObject theRoot = file.getRootObject(); 1803 1804 if (theRoot == null) { 1805 log.debug("findObject(): rootObject is null"); 1806 return null; 1807 } 1808 else if (path.equals("/")) { 1809 log.debug("findObject() path is rootObject"); 1810 return theRoot; 1811 } 1812 1813 Iterator<HObject> member_it = ((Group) theRoot).breadthFirstMemberList().iterator(); 1814 HObject theObj = null; 1815 while (member_it.hasNext()) { 1816 theObj = member_it.next(); 1817 String fullPath = theObj.getFullName() + "/"; 1818 1819 if (path.equals(fullPath) && theObj.getPath() != null) 1820 break; 1821 else 1822 theObj = null; 1823 } 1824 1825 return theObj; 1826 } 1827 1828 // //////////////////////////////////////////////////////////////////////////////////// 1829 // Added to support HDF5 1.8 features // 1830 // //////////////////////////////////////////////////////////////////////////////////// 1831 1832 /** 1833 * Opens file and returns a file identifier. 1834 * 1835 * @param indexList 1836 * The property list is the list of parameters, like index type 1837 * and the index order. The index type can be alphabetical or 1838 * creation. The index order can be increasing order or 1839 * decreasing order. 1840 * 1841 * @return File identifier if successful; otherwise -1. 1842 * 1843 * @throws Exception 1844 * The exceptions thrown vary depending on the implementing class. 1845 */ 1846 public long open(int... indexList) throws Exception { 1847 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:open."); 1848 } 1849 1850 /** 1851 * Creates a new group with specified name in existing group. 1852 * 1853 * If the parent group is null, the new group will be created in the root 1854 * group. 1855 * 1856 * @param name 1857 * The name of a new group. 1858 * @param pgroup 1859 * The parent group object. 1860 * @param gplist 1861 * The group creation properties, in which the order of the 1862 * properties conforms the HDF5 library API, H5Gcreate(), i.e. 1863 * lcpl, gcpl and gapl, where 1864 * <ul> 1865 * <li>lcpl : Property list for link creation <li>gcpl : Property 1866 * list for group creation <li>gapl : Property list for group access 1867 * </ul> 1868 * 1869 * @return The new group if successful; otherwise returns null. 1870 * 1871 * @throws Exception 1872 * The exceptions thrown vary depending on the implementing class. 1873 */ 1874 public Group createGroup(String name, Group pgroup, long... gplist) throws Exception { 1875 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:createGroup."); 1876 } 1877 1878 /*** 1879 * Creates the group creation property list identifier, gcpl. This 1880 * identifier is used when creating Groups. 1881 * 1882 * @param creationorder 1883 * The order in which the objects in a group should be created. 1884 * It can be Tracked or Indexed. 1885 * @param maxcompact 1886 * The maximum number of links to store in the group in a compact format. 1887 * @param mindense 1888 * The minimum number of links to store in the indexed 1889 * format.Groups which are in indexed format and in which the 1890 * number of links falls below this threshold are automatically 1891 * converted to compact format. 1892 * 1893 * @return The gcpl identifier. 1894 * 1895 * @throws Exception 1896 * The exceptions thrown vary depending on the implementing class. 1897 */ 1898 public long createGcpl(int creationorder, int maxcompact, int mindense) throws Exception { 1899 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:createGcpl."); 1900 } 1901 1902 /** 1903 * Creates a link to an existing object in the open file. 1904 * 1905 * If linkGroup is null, the new link is created in the root group. 1906 * 1907 * @param linkGroup 1908 * The group where the link is created. 1909 * @param name 1910 * The name of the link. 1911 * @param currentObj 1912 * The existing object the new link will reference. 1913 * 1914 * @return The object pointed to by the new link if successful; 1915 * otherwise returns null. 1916 * 1917 * @throws Exception 1918 * The exceptions thrown vary depending on the implementing class. 1919 */ 1920 public HObject createLink(Group linkGroup, String name, Object currentObj) throws Exception { 1921 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:createLink."); 1922 } 1923 1924 /** 1925 * Export dataset. 1926 * 1927 * @param file_export_name 1928 * The file name to export data into. 1929 * @param object 1930 * The HDF5 dataset object. 1931 * @param binary_order 1932 * The data byte order 1933 * 1934 * @throws Exception 1935 * The exceptions thrown vary depending on the implementing class. 1936 */ 1937 public void exportDataset(String file_export_name, Dataset object, int binary_order) throws Exception { 1938 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:exportDataset."); 1939 } 1940 1941 /** 1942 * Renames an attribute. 1943 * 1944 * @param obj 1945 * The object whose attribute is to be renamed. 1946 * @param oldAttrName 1947 * The current name of the attribute. 1948 * @param newAttrName 1949 * The new name of the attribute. 1950 * 1951 * @throws Exception 1952 * The exceptions thrown vary depending on the implementing class. 1953 */ 1954 public void renameAttribute(HObject obj, String oldAttrName, String newAttrName) throws Exception { 1955 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:renameAttribute."); 1956 } 1957 1958 /** 1959 * Sets the bounds of new library versions. 1960 * 1961 * @param lowStr 1962 * The earliest version of the library. 1963 * @param highStr 1964 * The latest version of the library. 1965 * 1966 * @throws Exception 1967 * The exceptions thrown vary depending on the implementing class. 1968 */ 1969 public void setNewLibBounds(String lowStr, String highStr) throws Exception { 1970 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setNewLibBounds."); 1971 } 1972 1973 /** 1974 * Sets the bounds of library versions. 1975 * 1976 * @param lowStr 1977 * The earliest version of the library. 1978 * @param highStr 1979 * The latest version of the library. 1980 * 1981 * @throws Exception 1982 * The exceptions thrown vary depending on the implementing class. 1983 */ 1984 public void setLibBounds(String lowStr, String highStr) throws Exception { 1985 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setLibBounds."); 1986 } 1987 1988 /** 1989 * Gets the bounds of library versions 1990 * 1991 * @return The earliest and latest library versions in an int array. 1992 * 1993 * @throws Exception 1994 * The exceptions thrown vary depending on the implementing class. 1995 */ 1996 public int[] getLibBounds() throws Exception { 1997 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getLibBounds."); 1998 } 1999 2000 /** 2001 * Initialize the bounds of library versions 2002 * 2003 * @throws Exception 2004 * The exceptions thrown vary depending on the implementing class. 2005 */ 2006 public void initLibBounds() throws Exception { 2007 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:initLibBounds."); 2008 } 2009 2010 /** 2011 * Gets the bounds of library versions as text. 2012 * 2013 * @return libversion The earliest and latest version of the library. 2014 * 2015 * @throws Exception 2016 * The exceptions thrown vary depending on the implementing class. 2017 */ 2018 public String getLibBoundsDescription() throws Exception { 2019 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getLibBoundsDescription."); 2020 } 2021 2022 /** @return the int value of the index type value. 2023 * 2024 * @param strtype 2025 * The name of the index type. 2026 * 2027 * @throws Exception 2028 * The exceptions thrown vary depending on the implementing class. 2029 */ 2030 public static int getIndexTypeValue(String strtype) throws Exception { 2031 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexTypeValue."); 2032 } 2033 2034 /** @return the int value of the index type. 2035 * 2036 * @param strtype 2037 * The name of the index type. 2038 * 2039 * @throws Exception 2040 * The exceptions thrown vary depending on the implementing class. 2041 */ 2042 public int getIndexType(String strtype) throws Exception { 2043 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexType."); 2044 } 2045 2046 /** set the int value of the index type. 2047 * 2048 * @param indexType 2049 * The value of the index type. 2050 * 2051 * @throws Exception 2052 * The exceptions thrown vary depending on the implementing class. 2053 */ 2054 public void setIndexType(int indexType) throws Exception { 2055 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setIndexType."); 2056 } 2057 2058 /** @return the int value of the index order value. 2059 * 2060 * @param strorder 2061 * The name of the index order. 2062 * 2063 * @throws Exception 2064 * The exceptions thrown vary depending on the implementing class. 2065 */ 2066 public static int getIndexOrderValue(String strorder) throws Exception { 2067 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexOrderValue."); 2068 } 2069 2070 /** @return the int value of the index order. 2071 * 2072 * @param strorder 2073 * The name of the index order. 2074 * 2075 * @throws Exception 2076 * The exceptions thrown vary depending on the implementing class. 2077 */ 2078 public int getIndexOrder(String strorder) throws Exception { 2079 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:getIndexOrder."); 2080 } 2081 2082 /** set the int value of the index order. 2083 * 2084 * @param indexOrder 2085 * The index order. 2086 * 2087 * @throws Exception 2088 * The exceptions thrown vary depending on the implementing class. 2089 */ 2090 public void setIndexOrder(int indexOrder) throws Exception { 2091 throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement FileFormat:setIndexOrder."); 2092 } 2093}