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