001 /* @(#)FitsFile.java $Revision: 1.10 $ $Date: 2003/04/11 08:41:15 $ 002 * 003 * Copyright (C) 2002 European Southern Observatory 004 * License: GNU General Public License version 2 or later 005 */ 006 package org.eso.fits; 007 008 import java.lang.*; 009 import java.util.*; 010 import java.io.*; 011 012 /** FitsFile class represents a FITS file consisting of a set of 013 * Header/Data Units. The header information is stored in 014 * FitsHeader objects while data are not saved in objects but 015 * accessed through file. Thus, files may be corrupted if the 016 * disk file is modified independently by other modules. 017 * 018 * @version $Revision: 1.10 $ $Date: 2003/04/11 08:41:15 $ 019 * @author P.Grosbol, DMD/ESO, <pgrosbol@eso.org> http://www.eso.org/~pgrosbol/fits_java/jfits.html 020 */ 021 public class FitsFile { 022 023 private File file; 024 private RandomAccessFile raFile; 025 private Vector hdUnits; 026 private boolean changeHDU = false; 027 028 /** Default constructor for FitsFile class 029 */ 030 public FitsFile() { 031 hdUnits = new Vector(1); 032 } 033 034 /** Constructor for FitsFile class given a FITS stream. 035 * 036 * 037 * @param file DataInput stream positioned at its start 038 * @exception FitsException */ 039 public FitsFile(DataInput file) throws FitsException { 040 this(); 041 scanFitsFile(file, false); 042 } 043 044 /** Constructor for FitsFile class given a FITS stream and a flag 045 * indicating if the data matrices should be stored internally. 046 * The store flag must be true to allow access to the data matrices 047 * where as header data will always be available. 048 * 049 * @param file DataInput stream positioned at its start 050 * @param sflag Flag indicating if data matrices should be 051 * stored internally in the class. 052 * @exception FitsException */ 053 public FitsFile(DataInput file, boolean sflag) throws FitsException { 054 this(); 055 scanFitsFile(file, sflag); 056 } 057 058 /** Constructor specifying a name of a disk file. Note: the file 059 * will be opened in read-only mode for security reasons. This 060 * means that the data matrix cannot be modified although headers 061 * can as they are stored in memory. If data should be modified, 062 * one must create a DataInput object for the file explicitly 063 * (with read/write permissions) and use the appropriate 064 * constructor. 065 * 066 * @param file name of disk file in FITS format 067 * @exception IOException,FitsException */ 068 public FitsFile(File file) throws IOException, FitsException { 069 this(); 070 this.raFile = new RandomAccessFile(file, "r"); 071 this.file = file; 072 scanFitsFile(raFile, false); 073 } 074 075 /** Constructor from name of disk file. Note: the file will be 076 * opened in read-only mode for security reasons. This means 077 * that the data matrix cannot be modified although headers can 078 * as they are stored in memory. If data should be modified, one 079 * must create a DataInput object for the file explicitly (with 080 * read/write permissions) and use the appropriate constructor. 081 * 082 * @param filename name of disk file in FITS format 083 * @exception IOException,FitsException */ 084 public FitsFile(String filename) throws IOException, FitsException { 085 this(new File(filename)); 086 } 087 088 /** Private method which scans an input stream. It is used by the 089 * constructors. 090 * @param file DataInput file positioned at its start 091 * @param sflag Flag for internal storage of data matrices 092 * @exception FitsException */ 093 private void scanFitsFile(DataInput file, boolean sflag) 094 throws FitsException { 095 FitsHDUnit hdu; 096 int no_hdu = 0; 097 098 try { 099 while (true) { 100 hdu = new FitsHDUnit(file, sflag); 101 hdUnits.setSize(no_hdu++); 102 hdUnits.addElement(hdu); 103 } 104 } catch (FitsException e) { 105 if (no_hdu<1) { 106 throw new FitsException("Not a FITS file (" + e + ")", FitsException.FILE); 107 } 108 } 109 hdUnits.trimToSize(); 110 } 111 112 /** Finalize method which close disk file 113 * 114 * @exception IOException */ 115 protected void finalize() throws IOException { 116 if (raFile != null) raFile.close(); 117 file = null; 118 } 119 120 /** Static method to test if a disk file possibly is in FITS format. 121 * The test is trivial in the sense that the file may not be a correct 122 * FITS file even if 'true' is returned. On the other hand, it is 123 * certainly not a FITS file if 'false' is returned. 124 * 125 * @param file disk file */ 126 public static boolean isFitsFile(File file) { 127 int nb = 0; 128 byte[] card = new byte[Fits.CARD]; 129 try { 130 RandomAccessFile raf = new RandomAccessFile(file, "r"); 131 nb = raf.read(card); 132 raf.close(); 133 } catch (IOException e) { 134 return false; 135 } 136 if (nb<Fits.CARD) { 137 return false; 138 } 139 String str = new String(card); 140 return str.startsWith("SIMPLE = "); 141 } 142 143 /** Static method to test if a disk file possibly is in FITS format. 144 * The test is trivial in the sense that the file may not be a correct 145 * FITS file even if 'true' is returned. On the other hand, it is 146 * certainly not a FITS file if 'false' is returned. 147 * 148 * @param filename name of disk file */ 149 public static boolean isFitsFile(String filename) { 150 return isFitsFile(new File(filename)); 151 } 152 153 /** Add new HDUnit to FITS file. 154 * 155 * @param hdu FitsHDUnit to be added */ 156 public void addHDUnit(FitsHDUnit hdu) { 157 hdUnits.addElement(hdu); 158 changeHDU = true; 159 } 160 161 /** Insert new HDUnit to FITS file at specified location. 162 * 163 * @param hdu FitsHDUnit to be inserted 164 * @param index location at which hte HDU should be inserted */ 165 public void insertHDUnitAt(FitsHDUnit hdu, int index) { 166 hdUnits.insertElementAt(hdu, index); 167 changeHDU = true; 168 } 169 170 /** Remove HDUnit with given location from FITS file. 171 * 172 * @param index location of the HDU to be removed */ 173 public void removeHDUnitAt(int index) { 174 hdUnits.removeElementAt(index); 175 changeHDU = true; 176 } 177 178 /** Get HDUnit in FitsFile by its position. If the position is 179 * less that 0, the first HDU is returned while the last is given 180 * for positions beyond the actual number. 181 * 182 * @param no number of HDUnit to retrieve (starting with 0) */ 183 final public FitsHDUnit getHDUnit(int no){ 184 int n = 0; 185 186 if (no<0) { 187 return (FitsHDUnit) hdUnits.firstElement(); 188 } else if (no>=hdUnits.size()) { 189 return (FitsHDUnit) hdUnits.lastElement(); 190 } 191 192 FitsHDUnit hdu; 193 Enumeration enumeration = hdUnits.elements(); 194 while (enumeration.hasMoreElements()) { 195 hdu = (FitsHDUnit) enumeration.nextElement(); 196 if (n==no) return hdu; 197 n++; 198 } 199 return (FitsHDUnit) hdUnits.lastElement(); 200 } 201 202 /** Save changes made to a FITS file on disk. The FitsFile must have 203 * been creaded from a read/write RandomAccess disk file. 204 * Further, headers and data must fit into the original file. 205 * Not check is done to verify the correctness of the FITS headers. 206 * 207 * @exception IOException, FitsException */ 208 public void saveFile() throws IOException,FitsException { 209 if (changeHDU) { 210 throw new FitsException("HD Units of file have been changes", 211 FitsException.FILE); 212 } 213 Enumeration enumeration = hdUnits.elements(); 214 while (enumeration.hasMoreElements()) { 215 if (!((FitsHDUnit) enumeration.nextElement()).canSave()) { 216 throw new FitsException("No space in FITS header", 217 FitsException.NOHEADERSPACE); 218 } 219 } 220 221 RandomAccessFile raf = new RandomAccessFile(file, "rw"); 222 223 enumeration = hdUnits.elements(); 224 while (enumeration.hasMoreElements()) { 225 ((FitsHDUnit)enumeration.nextElement()).saveFile(raf); 226 } 227 raf.close(); 228 } 229 230 /** Write FITS file to a DataOutput stream. Not check is done to verify 231 * the correctness of the FITS headers. 232 * 233 * @param file the data output to be written 234 * @exception IOException, FitsException */ 235 public void writeFile(DataOutput file) throws IOException,FitsException { 236 Enumeration enumeration = hdUnits.elements(); 237 while (enumeration.hasMoreElements()) { 238 ((FitsHDUnit)enumeration.nextElement()).writeFile(file); 239 } 240 } 241 242 /** Write FITS file on a new diskfile. Not check is done to verify 243 * the correctness of the FITS headers. 244 * 245 * @param file new file to be written 246 * @exception IOException, FitsException */ 247 public void writeFile(File file) throws IOException,FitsException { 248 if (file == null) { 249 throw new FitsException("Cannot write to null-pointer file", 250 FitsException.FILE); 251 } 252 if (file.exists()) { 253 if (!file.isFile()) { 254 throw new FitsException("Cannot overwrite special file", 255 FitsException.FILE); 256 } 257 if ((this.file != null) 258 && this.file.getCanonicalPath().equals( 259 file.getCanonicalPath())) { 260 throw new FitsException("Cannot overwrite itself", 261 FitsException.FILE); 262 } 263 } 264 RandomAccessFile raf = new RandomAccessFile(file, "rw"); 265 writeFile(raf); 266 raf.close(); 267 } 268 269 /** Write FITS file on a new diskfile. Not check is done to verify 270 * the correctness of the FITS headers. 271 * 272 * @param filename name of new file to be written 273 * @exception IOException, FitsException */ 274 public void writeFile(String filename) throws IOException,FitsException { 275 writeFile(new File(filename)); 276 } 277 278 /** Remove all references to associated DataInput files. */ 279 public void closeFile() { 280 Enumeration enumeration = hdUnits.elements(); 281 while (enumeration.hasMoreElements()) { 282 ((FitsHDUnit)enumeration.nextElement()).closeFile(); 283 } 284 if (raFile != null) { 285 try { 286 raFile.close(); 287 } catch (IOException e) { 288 } 289 } 290 this.file = null; 291 } 292 293 /** Gets numnber of HDUnits in FITS file */ 294 final public int getNoHDUnits(){ 295 return hdUnits.size(); 296 } 297 298 /** Gets Canonical path of FITS file */ 299 public String getName(){ 300 String name = ""; 301 if (file != null) { 302 try { 303 name = file.getCanonicalPath(); 304 } catch (IOException e) { 305 name = file.getAbsolutePath(); 306 } 307 } 308 return name; 309 } 310 311 /** Gets file identifier for FITS file */ 312 public File getFile(){ 313 return file; 314 } 315 } 316 317 318 319