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 */ 013 014package cz.dhl.ftp; 015 016import cz.dhl.ui.CoConsole; 017import java.io.OutputStream; 018import java.io.IOException; 019 020/** 021 * Allows writing into FTP file. 022 * 023 * @Version 0.70 01/04/2002 024 * @author Bea Petrovicova <beapetrovicova@yahoo.com> 025 * @see Ftp 026 * @see FtpFile 027 */ 028public final class FtpOutputStream extends OutputStream 029{ Ftp client; 030 private FtpDataSocket data; 031 private OutputStream stream; 032 033 /** Opens 'store' OutputStream for given filename. 034 * <P>This constructor behaves similarly to 035 * <code>{@link #FtpOutputStream(FtpFile,boolean)}</code>.</P> 036 * @param file the file to be opened for writing 037 * @exception IOException socket error */ 038 public FtpOutputStream(FtpFile file) throws IOException { this(file,false); } 039 040 /** Open either 'store' or 'append' OutputStream for given filename. 041 * <P><B>STOR</B> - store</P> 042 * <P>This command causes the server-DTP to accept the data 043 * transferred via the data connection and to store the data 044 * as a file at the server site. If the file specified in the 045 * pathname exists at the server site, then its contents shall 046 * be replaced by the data being transferred. A new file is 047 * created at the server site if the file specified in the 048 * pathname does not already exist.</P> 049 * <P><B>APPE</B> - append (with create)</P> 050 * <P>This command causes the server-DTP to accept the data 051 * transferred via the data connection and to store the data 052 * in a file at the server site. If the file specified in the 053 * pathname exists at the server site, then the data shall be 054 * appended to that file; otherwise the file specified in the 055 * pathname shall be created at the server site.</P> 056 * @param file the file to be opened for writing 057 * @param append if true, then bytes will be written to the 058 * end of the file rather than the beginning 059 * @exception IOException socket error */ 060 public FtpOutputStream(FtpFile file,boolean append) throws IOException 061 { client=null; 062 data=new FtpDataSocket(file.client); 063 if(append) stream=data.getOutputStream("APPE " +file,file.getDataType()); 064 else stream=data.getOutputStream("STOR " +file,file.getDataType()); } 065 066 /** Opens 'store' concurent OutputStream for given filename. 067 * <P>This constructor behaves similarly to 068 * <code>{@link #FtpOutputStream(FtpFile,FtpConnect,CoConsole,boolean)}</code>.</P> 069 * @param file the file to be opened for writing 070 * @param connect login details 071 * @param console message output 072 * @exception IOException socket error */ 073 public FtpOutputStream(FtpFile file,FtpConnect connect,CoConsole console) 074 throws IOException { this(file,connect,console,false); } 075 076 /** Open either 'store' or 'append' concurent OutputStream for given filename. 077 * <P>Single ftp connection cannot handle <B>multiple concurent 078 * data transfers</B>. This limitation can be eliminated by 079 * creating new ftp connection for each concurent data 080 * transfer. This constructor creates separate Ftp instance.</P> 081 * <P>Note (1) supplying same CoConsole instance for 082 * multiple sessions will produce messed output.</P> 083 * <P>Note (2) This code may need to be run in separate 084 * thread to process multiple files concurently.</P> 085 * <P><B>STOR</B> - store</P> 086 * <P>This command causes the server-DTP to accept the data 087 * transferred via the data connection and to store the data 088 * as a file at the server site. If the file specified in the 089 * pathname exists at the server site, then its contents shall 090 * be replaced by the data being transferred. A new file is 091 * created at the server site if the file specified in the 092 * pathname does not already exist.</P> 093 * <P><B>APPE</B> - append (with create)</P> 094 * <P>This command causes the server-DTP to accept the data 095 * transferred via the data connection and to store the data 096 * in a file at the server site. If the file specified in the 097 * pathname exists at the server site, then the data shall be 098 * appended to that file; otherwise the file specified in the 099 * pathname shall be created at the server site.</P> 100 * @param file the file to be opened for writing 101 * @param connect login details 102 * @param console message output 103 * @param append if true, then bytes will be written to the 104 * end of the file rather than the beginning 105 * @exception IOException socket error 106 * @see #FtpOutputStream(FtpFile,boolean) */ 107 public FtpOutputStream 108 (FtpFile file,FtpConnect connect,CoConsole console,boolean append) 109 throws IOException 110 { client = new Ftp(); 111 if(client.connect(connect)) 112 { if(console!=null) 113 client.getContext().setConsole(console); 114 file = new FtpFile(file.toString(),client); 115 data=new FtpDataSocket(file.client); 116 if(append) stream=data.getOutputStream("APPE " +file,file.getDataType()); 117 else stream=data.getOutputStream("STOR " +file,file.getDataType()); 118 } else throw new IOException("Connect failed."); 119 } 120 121 /* <P><B>STOU</B> - store unique</P> 122 * <P>This command behaves like STOR except that the resultant 123 * file is to be created in the current directory under a name 124 * unique to that directory. The 250 Transfer Started response 125 * must include the name generated.</P> */ 126 127 /** Close current data transfer and close data connection. 128 * <P>If no reply <B>ABOR</B> - abort</P> 129 * <P>This command tells the server to abort the previous FTP 130 * service command and any associated transfer of data. No 131 * action is to be taken if the previous command has been 132 * completed (including data transfer). The control connection 133 * is not to be closed by the server, but the data connection 134 * must be closed. There are two cases for the server upon 135 * receipt of this command:</P> 136 * <P>(1) the FTP service command was already completed. The 137 * server closes the data connection (if it is open) and 138 * responds with a 226 reply, indicating that the abort 139 * command was successfully processed.</P> 140 * <P>(2) the FTP service command is still in progress. The 141 * server aborts the FTP service in progress and closes the 142 * data connection, returning a 426 reply to indicate that 143 * the service request terminated abnormally. The server then 144 * sends a 226 reply, indicating that the abort command was 145 * successfully processed.</P> 146 * @exception IOException socket error */ 147 public void close() throws IOException 148 { IOException x = null; 149 while (stream!=null || data!=null || client!=null) 150 try 151 { OutputStream o; FtpDataSocket d; Ftp c; 152 if(stream!=null) { o=stream; stream = null; o.close(); } 153 if(data!=null) { d=data; data = null; d.close(); } 154 if(client!=null) { c=client; client = null; c.disconnect(); } 155 } catch(IOException e) { x=e; } 156 if(x!=null) throw x; 157 } 158 159 /** 160 * Writes the specified byte to this output stream. The general 161 * contract for <code>write</code> is that one byte is written 162 * to the output stream. The byte to be written is the eight 163 * low-order bits of the argument <code>b</code>. The 24 164 * high-order bits of <code>b</code> are ignored. 165 * 166 * @param b the <code>byte</code>. 167 * @exception IOException if an I/O error occurs. In particular, 168 * an <code>IOException</code> may be thrown if the 169 * output stream has been closed. 170 */ 171 public void write(int b) throws IOException { stream.write(b); } 172 173 /** 174 * Writes <code>b.length</code> bytes from the specified byte array 175 * to this output stream. The general contract for <code>write(b)</code> 176 * is that it should have exactly the same effect as the call 177 * <code>write(b, 0, b.length)</code>. 178 * 179 * @param b the data. 180 * @exception IOException if an I/O error occurs. 181 * @see cz.dhl.ftp.FtpOutputStream#write(byte[], int, int) 182 */ 183 public void write(byte b[]) throws IOException { stream.write(b); } 184 185 /** 186 * Writes <code>len</code> bytes from the specified byte array 187 * starting at offset <code>off</code> to this output stream. 188 * The general contract for <code>write(b, off, len)</code> is that 189 * some of the bytes in the array <code>b</code> are written to the 190 * output stream in order; element <code>b[off]</code> is the first 191 * byte written and <code>b[off+len-1]</code> is the last byte written 192 * by this operation. 193 * <p> 194 * The <code>write</code> method of <code>OutputStream</code> calls 195 * the write method of one argument on each of the bytes to be 196 * written out. Subclasses are encouraged to override this method and 197 * provide a more efficient implementation. 198 * <p> 199 * If <code>b</code> is <code>null</code>, a 200 * <code>NullPointerException</code> is thrown. 201 * <p> 202 * If <code>off</code> is negative, or <code>len</code> is negative, or 203 * <code>off+len</code> is greater than the length of the array 204 * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown. 205 * 206 * @param b the data. 207 * @param off the start offset in the data. 208 * @param len the number of bytes to write. 209 * @exception IOException if an I/O error occurs. In particular, 210 * an <code>IOException</code> is thrown if the output 211 * stream is closed. 212 */ 213 public void write(byte b[], int off, int len) throws IOException { stream.write(b,off,len); } 214 215 /** 216 * Flushes this output stream and forces any buffered output bytes 217 * to be written out. The general contract of <code>flush</code> is 218 * that calling it is an indication that, if any bytes previously 219 * written have been buffered by the implementation of the output 220 * stream, such bytes should immediately be written to their 221 * intended destination. 222 * 223 * @exception IOException if an I/O error occurs. 224 */ 225 public void flush() throws IOException { stream.flush(); } 226 227}