Index: FilePart.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v retrieving revision 1.2 diff -u -r1.2 FilePart.java --- FilePart.java 11 Oct 2002 05:16:32 -0000 1.2 +++ FilePart.java 17 Oct 2002 01:06:09 -0000 @@ -64,6 +64,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.FileNotFoundException; @@ -82,6 +83,7 @@ * * @author Matthew Albright * @author Jeff Dever + * @author Adrian Sutton * * @since 2.0 * @@ -91,12 +93,17 @@ //TODO: make this configurable static int MAX_BUFF_SIZE = 1 * 1024 * 1024; // 1 MiBs + private File file; private InputStream fileStream; private String fileName; private long fileLength; private String name; private int buff_size; + + private byte[] dataBuf = null; + private boolean bufferData = true; + private boolean markSupported = false; /** * Constructor. @@ -110,7 +117,8 @@ public FilePart(String name, File file) throws FileNotFoundException { - this( name, new FileInputStream(file), file.getName(), file.length() ); + // We create the input stream straight from the file later on. + this( name, null, file.getName(), file.length() ); if (! file.isFile()) { throw new FileNotFoundException("File is not a normal file."); @@ -119,16 +127,24 @@ if (! file.canRead()) { throw new FileNotFoundException("File is not readable."); } + + this.file = file; + this.bufferData = false; } /** - * FilePart Constructor. + * FilePart Constructor. This constructor should generally be + * avoided in favour of FilePart(String, java.io.File) as + * using an InputStream requires data to be buffered in RAM in case + * it needs to be resent. * * @param name the name for this part * @param fileInputStream an input stream for reading the file content * @param fileName the name of the file * @param fileLength the number of bytes contained in the file + * @see #getBufferData() + * @see #setBufferData(boolean) */ public FilePart( String name, @@ -145,7 +161,12 @@ this.fileStream = fileInputStream; this.fileName = fileName; this.fileLength = fileLength; - + // We need to cast fileLength to an int to call mark(int) on the + // input stream, so we must ensure that the file length will fit + // into an int before trying to use mark and reset. + this.markSupported = fileInputStream.markSupported() && + fileLength <= Integer.MAX_VALUE; + this.bufferData = !markSupported; } protected void sendHeader(OutputStream out) @@ -190,18 +211,65 @@ buff = new byte[(new Long(lengthOfData())).intValue()]; } - int len; - - while ((len = fileStream.read(buff)) != -1) - { - out.write(buff, 0, len); + InputStream is = fileStream; + if (markSupported) { + fileStream.mark((int)fileLength); + } + if (file != null) { + is = new FileInputStream(file); + } + if (dataBuf != null) { + // Send the buffered data from a previous send. + out.write(dataBuf, 0, dataBuf.length); + } else { + int len; + ByteArrayOutputStream bufferStream = null; + if (bufferData) { + bufferStream = new ByteArrayOutputStream(); + } + while ((len = is.read(buff)) != -1) { + out.write(buff, 0, len); + if (bufferData) { + bufferStream.write(buff, 0, len); + } + } + if (bufferData) { + dataBuf = bufferStream.toByteArray(); + } + if (markSupported) { + fileStream.reset(); + } } - } protected long lengthOfData() throws IOException { return fileLength; } + + /** + * Sets whether or not to buffer the data from the input stream so + * that it can be resent if nessecary during the connection. Note + * that this has no effect if this FilePart was constructed from a + * File object as a new FileInputStream will always be opened for + * each request. + * + * @param bufferData true if the data should be buffered in memory. + * @see #getBufferData() + */ + public void setBufferData(boolean bufferData) { + this.bufferData = bufferData; + } + + /** + * Returns whether or not data from the input stream is buffered in + * memory for this FilePart. + * + * @return true if the data will be buffered in memory. + * @see #setBufferData(boolean) + */ + public boolean getBufferData() { + return bufferData && file == null; + } }