001/* 002 * Version 0.70 01/04/2002 003 * 004 * Visit my url for update: http://www.geocities.com/beapetrovicova/ 005 * 006 * jFtp was developed by Bea Petrovicova <beapetrovicova@yahoo.com>. 007 * The design and implementation of jFtp are available for royalty-free 008 * adoption and use. This software is provided 'as is' without any 009 * guarantees. Copyright is retained by Bea Petrovicova. Redistribution 010 * of any part of jFtp or any derivative works must include this notice. 011 * 012 */ 013package cz.dhl.ftp; 014 015import cz.dhl.ui.CoConsole; 016import java.io.InputStream; 017import java.io.IOException; 018 019/** 020 * Allows reading from FTP file. 021 * 022 * @Version 0.70 01/04/2002 023 * @author Bea Petrovicova <beapetrovicova@yahoo.com> 024 * @see Ftp 025 * @see FtpFile 026 */ 027public class FtpInputStream extends InputStream 028{ Ftp client; 029 FtpDataSocket data; 030 InputStream stream; 031 032 FtpInputStream() {} 033 034 /** Open 'retreive' InputStream for given filename. 035 * <P><B>RETR</B> - retrieve</P> 036 * <P>This command causes the server-DTP to transfer a copy of 037 * the file, specified in the pathname, to the server or 038 * user-DTP at the other end of the data connection. 039 * The status and contents of the file at the server site 040 * shall be unaffected.</P> 041 * @param file the file to be opened for reading 042 * @exception IOException socket error 043 * @exception FileNotFoundException Server file not found. */ 044 public FtpInputStream(FtpFile file) 045 throws IOException 046 { client=null; 047 data=new FtpDataSocket(file.client); 048 stream=data.getInputStream("RETR " + file,file.getDataType()); } 049 050 /** Open 'retreive' concurent InputStream for given filename. 051 * <P>Single ftp connection cannot handle <B>multiple concurent 052 * data transfers</B>. This limitation can be eliminated by 053 * creating new ftp connection for each concurent data 054 * transfer. This constructor creates separate Ftp instance.</P> 055 * <P>Note (1) supplying same CoConsole instance for 056 * multiple sessions will produce messed output.</P> 057 * <P>Note (2) This code may need to be run in separate 058 * thread to process multiple files concurently.</P> 059 * <P><B>RETR</B> - retrieve</P> 060 * This command causes the server-DTP to transfer a copy of 061 * the file, specified in the pathname, to the server or 062 * user-DTP at the other end of the data connection. 063 * The status and contents of the file at the server site 064 * shall be unaffected.</P> 065 * @param file the file to be opened for reading 066 * @param connect login details 067 * @param console message output 068 * @exception IOException socket error 069 * @see #FtpInputStream(FtpFile) */ 070 public FtpInputStream(FtpFile file,FtpConnect connect,CoConsole console) 071 throws IOException 072 { client = new Ftp(); 073 if(client.connect(connect)) 074 { if(console!=null) 075 client.getContext().setConsole(console); 076 file = new FtpFile(file.toString(),client); 077 data=new FtpDataSocket(file.client); 078 stream=data.getInputStream("RETR " + file,file.getDataType()); 079 } else throw new IOException("Connect failed."); 080 } 081 082 /** Close current data transfer and close data connection. 083 * <P>If no reply <B>ABOR</B> - abort</P> 084 * <P>This command tells the server to abort the previous FTP 085 * service command and any associated transfer of data. No 086 * action is to be taken if the previous command has been 087 * completed (including data transfer). The control connection 088 * is not to be closed by the server, but the data connection 089 * must be closed. There are two cases for the server upon 090 * receipt of this command:</P> 091 * <P>(1) the FTP service command was already completed. The 092 * server closes the data connection (if it is open) and 093 * responds with a 226 reply, indicating that the abort 094 * command was successfully processed.</P> 095 * <P>(2) the FTP service command is still in progress. The 096 * server aborts the FTP service in progress and closes the 097 * data connection, returning a 426 reply to indicate that 098 * the service request terminated abnormally. The server then 099 * sends a 226 reply, indicating that the abort command was 100 * successfully processed.</P> 101 * @exception IOException socket error */ 102 public void close() throws IOException 103 { IOException x = null; 104 while (stream!=null || data!=null || client!=null) 105 try 106 { InputStream i; FtpDataSocket d; Ftp c; 107 if(stream!=null) { i=stream; stream = null; i.close(); } 108 if(data!=null) { d=data; data = null; d.close(); } 109 if(client!=null) { c=client; client = null; c.disconnect(); } 110 } catch(IOException e) { x=e; } 111 if(x!=null) throw x; 112 } 113 114 /** 115 * Reads the next byte of data from the input stream. The value byte is 116 * returned as an <code>int</code> in the range <code>0</code> to 117 * <code>255</code>. If no byte is available because the end of the stream 118 * has been reached, the value <code>-1</code> is returned. This method 119 * blocks until input data is available, the end of the stream is detected, 120 * or an exception is thrown. 121 * 122 * @return the next byte of data, or <code>-1</code> if the end of the 123 * stream is reached. 124 * @exception IOException if an I/O error occurs. 125 */ 126 public int read() throws IOException { return stream.read(); } 127 128 /** 129 * Reads some number of bytes from the input stream and stores them into 130 * the buffer array <code>b</code>. The number of bytes actually read is 131 * returned as an integer. This method blocks until input data is 132 * available, end of file is detected, or an exception is thrown. 133 * 134 * <p> If <code>b</code> is <code>null</code>, a 135 * <code>NullPointerException</code> is thrown. If the length of 136 * <code>b</code> is zero, then no bytes are read and <code>0</code> is 137 * returned; otherwise, there is an attempt to read at least one byte. If 138 * no byte is available because the stream is at end of file, the value 139 * <code>-1</code> is returned; otherwise, at least one byte is read and 140 * stored into <code>b</code>. 141 * 142 * <p> The first byte read is stored into element <code>b[0]</code>, the 143 * next one into <code>b[1]</code>, and so on. The number of bytes read is, 144 * at most, equal to the length of <code>b</code>. Let <i>k</i> be the 145 * number of bytes actually read; these bytes will be stored in elements 146 * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>, 147 * leaving elements <code>b[</code><i>k</i><code>]</code> through 148 * <code>b[b.length-1]</code> unaffected. 149 * 150 * <p> If the first byte cannot be read for any reason other than end of 151 * file, then an <code>IOException</code> is thrown. In particular, an 152 * <code>IOException</code> is thrown if the input stream has been closed. 153 * 154 * <p> The <code>read(b)</code> method for class <code>InputStream</code> 155 * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre> 156 * 157 * @param b the buffer into which the data is read. 158 * @return the total number of bytes read into the buffer, or 159 * <code>-1</code> is there is no more data because the end of 160 * the stream has been reached. 161 * @exception IOException if an I/O error occurs. 162 * @see cz.dhl.ftp.FtpInputStream#read(byte[], int, int) 163 */ 164 public int read(byte b[]) throws IOException { return stream.read(b); } 165 166 /** 167 * Reads up to <code>len</code> bytes of data from the input stream into 168 * an array of bytes. An attempt is made to read as many as 169 * <code>len</code> bytes, but a smaller number may be read, possibly 170 * zero. The number of bytes actually read is returned as an integer. 171 * 172 * <p> This method blocks until input data is available, end of file is 173 * detected, or an exception is thrown. 174 * 175 * <p> If <code>b</code> is <code>null</code>, a 176 * <code>NullPointerException</code> is thrown. 177 * 178 * <p> If <code>off</code> is negative, or <code>len</code> is negative, or 179 * <code>off+len</code> is greater than the length of the array 180 * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is 181 * thrown. 182 * 183 * <p> If <code>len</code> is zero, then no bytes are read and 184 * <code>0</code> is returned; otherwise, there is an attempt to read at 185 * least one byte. If no byte is available because the stream is at end of 186 * file, the value <code>-1</code> is returned; otherwise, at least one 187 * byte is read and stored into <code>b</code>. 188 * 189 * <p> The first byte read is stored into element <code>b[off]</code>, the 190 * next one into <code>b[off+1]</code>, and so on. The number of bytes read 191 * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of 192 * bytes actually read; these bytes will be stored in elements 193 * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>, 194 * leaving elements <code>b[off+</code><i>k</i><code>]</code> through 195 * <code>b[off+len-1]</code> unaffected. 196 * 197 * <p> In every case, elements <code>b[0]</code> through 198 * <code>b[off]</code> and elements <code>b[off+len]</code> through 199 * <code>b[b.length-1]</code> are unaffected. 200 * 201 * <p> If the first byte cannot be read for any reason other than end of 202 * file, then an <code>IOException</code> is thrown. In particular, an 203 * <code>IOException</code> is thrown if the input stream has been closed. 204 * 205 * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method 206 * for class <code>InputStream</code> simply calls the method 207 * <code>read()</code> repeatedly. If the first such call results in an 208 * <code>IOException</code>, that exception is returned from the call to 209 * the <code>read(b,</code> <code>off,</code> <code>len)</code> method. If 210 * any subsequent call to <code>read()</code> results in a 211 * <code>IOException</code>, the exception is caught and treated as if it 212 * were end of file; the bytes read up to that point are stored into 213 * <code>b</code> and the number of bytes read before the exception 214 * occurred is returned. Subclasses are encouraged to provide a more 215 * efficient implementation of this method. 216 * 217 * @param b the buffer into which the data is read. 218 * @param off the start offset in array <code>b</code> 219 * at which the data is written. 220 * @param len the maximum number of bytes to read. 221 * @return the total number of bytes read into the buffer, or 222 * <code>-1</code> if there is no more data because the end of 223 * the stream has been reached. 224 * @exception IOException if an I/O error occurs. 225 * @see cz.dhl.ftp.FtpInputStream#read() 226 */ 227 public int read(byte b[], int off, int len) throws IOException { return stream.read(b,off,len); } 228 229 /** 230 * Skips over and discards <code>n</code> bytes of data from this input 231 * stream. The <code>skip</code> method may, for a variety of reasons, end 232 * up skipping over some smaller number of bytes, possibly <code>0</code>. 233 * This may result from any of a number of conditions; reaching end of file 234 * before <code>n</code> bytes have been skipped is only one possibility. 235 * The actual number of bytes skipped is returned. If <code>n</code> is 236 * negative, no bytes are skipped. 237 * 238 * @param n the number of bytes to be skipped. 239 * @return the actual number of bytes skipped. 240 * @exception IOException if an I/O error occurs. 241 */ 242 public long skip(long n) throws IOException { return stream.skip(n); } 243 244 /** 245 * Returns the number of bytes that can be read (or skipped over) from 246 * this input stream without blocking by the next caller of a method for 247 * this input stream. The next caller might be the same thread or or 248 * another thread. 249 * 250 * <p> The <code>available</code> method for class <code>InputStream</code> 251 * always returns <code>0</code>. 252 * 253 * @return the number of bytes that can be read from this input stream 254 * without blocking. 255 * @exception IOException if an I/O error occurs. 256 */ 257 public int available() throws IOException { return stream.available(); } 258 259 /** 260 * Marks the current position in this input stream. A subsequent call to 261 * the <code>reset</code> method repositions this stream at the last marked 262 * position so that subsequent reads re-read the same bytes. 263 * 264 * <p> The <code>readlimit</code> arguments tells this input stream to 265 * allow that many bytes to be read before the mark position gets 266 * invalidated. 267 * 268 * <p> The general contract of <code>mark</code> is that, if the method 269 * <code>markSupported</code> returns <code>true</code>, the stream somehow 270 * remembers all the bytes read after the call to <code>mark</code> and 271 * stands ready to supply those same bytes again if and whenever the method 272 * <code>reset</code> is called. However, the stream is not required to 273 * remember any data at all if more than <code>readlimit</code> bytes are 274 * read from the stream before <code>reset</code> is called. 275 * 276 * @param readlimit the maximum limit of bytes that can be read before 277 * the mark position becomes invalid. 278 * @see cz.dhl.ftp.FtpInputStream#reset() 279 */ 280 public synchronized void mark(int readlimit) { stream.mark(readlimit); } 281 282 /** 283 * Repositions this stream to the position at the time the 284 * <code>mark</code> method was last called on this input stream. 285 * 286 * <p> The general contract of <code>reset</code> is: 287 * 288 * <p><ul> 289 * 290 * <li> If the method <code>markSupported</code> returns 291 * <code>true</code>, then: 292 * 293 * <ul><li> If the method <code>mark</code> has not been called since 294 * the stream was created, or the number of bytes read from the stream 295 * since <code>mark</code> was last called is larger than the argument 296 * to <code>mark</code> at that last call, then an 297 * <code>IOException</code> might be thrown. 298 * 299 * <li> If such an <code>IOException</code> is not thrown, then the 300 * stream is reset to a state such that all the bytes read since the 301 * most recent call to <code>mark</code> (or since the start of the 302 * file, if <code>mark</code> has not been called) will be resupplied 303 * to subsequent callers of the <code>read</code> method, followed by 304 * any bytes that otherwise would have been the next input data as of 305 * the time of the call to <code>reset</code>. </ul> 306 * 307 * <li> If the method <code>markSupported</code> returns 308 * <code>false</code>, then: 309 * 310 * <ul><li> The call to <code>reset</code> may throw an 311 * <code>IOException</code>. 312 * 313 * <li> If an <code>IOException</code> is not thrown, then the stream 314 * is reset to a fixed state that depends on the particular type of the 315 * input stream and how it was created. The bytes that will be supplied 316 * to subsequent callers of the <code>read</code> method depend on the 317 * particular type of the input stream. </ul></ul> 318 * 319 * @exception IOException if this stream has not been marked or if the 320 * mark has been invalidated. 321 * @see cz.dhl.ftp.FtpInputStream#mark(int) 322 * @see java.io.IOException 323 */ 324 public synchronized void reset() throws IOException { stream.reset(); } 325 326 /** 327 * Tests if this input stream supports the <code>mark</code> and 328 * <code>reset</code> methods. 329 * 330 * @return <code>true</code> if this true type supports the mark and reset 331 * method; <code>false</code> otherwise. 332 * @see cz.dhl.ftp.FtpInputStream#mark(int) 333 * @see cz.dhl.ftp.FtpInputStream#reset() 334 */ 335 public boolean markSupported() { return stream.markSupported(); } 336 337}