Soy extremadamente nuevo a Java, y he estado enseñándome sobre la marcha, así que comencé a crear un applet. Me gustaría crear uno que pueda seleccionar un archivo del disco local y cargarlo como una solicitud POST multipart/form-data pero con una barra de progreso. Obviamente, el usuario debe otorgar permiso al applet de Java para acceder al disco duro. Ahora ya tengo funcionando la primera parte: el usuario puede seleccionar un archivo utilizando un objeto JFileChooser
, que devuelve convenientemente un objeto File
. Pero me pregunto qué vendrá después. Sé que File.length()
me dará el tamaño total en bytes del archivo, pero ¿cómo envío el File
seleccionado a la web, y cómo puedo monitorear cuántos bytes se han enviado? Gracias por adelantado.Subida de archivos con Java (con barra de progreso)
Respuesta
Terminé tropezando con un applet de carga de código abierto de Java y encontré todo lo que necesitaba saber dentro de su código. A continuación se presentan enlaces a un blog que lo describen, así como la fuente:
Mire en HTTP Client para cargar el archivo a la web. Debería ser capaz de hacer eso. No estoy seguro de cómo obtener la barra de progreso, pero implicaría consultar esa API de alguna manera.
Puede que este article le ayude. Explica en detalle usando HttpClient y FileUpload, ambos proyectos de apache para hacer lo que quiera. También incluye muestras de código.
Según lo observado por el artículo publicado por Vincent, puede utilizar Apache commons para hacer esto.
Poco cortó
DiskFileUpload upload = new DiskFileUpload();
upload.setHeaderEncoding(ConsoleConstants.UTF8_ENCODING);
upload.setSizeMax(1000000);
upload.setSizeThreshold(1000000);
Iterator it = upload.parseRequest((HttpServletRequest) request).iterator();
FileItem item;
while(it.hasNext()){
item = (FileItem) it.next();
if (item.getFieldName("UPLOAD FIELD"){
String fileName = item.getString(ConsoleConstants.UTF8_ENCODING);
byte[] fileBytes = item.get();
}
}
Tenga en cuenta que la barra de progreso podría inducir a error cuando consume un componente intermedio en la red (por ejemplo, el proxy HTTP de un ISP, o un proxy HTTP inverso delante del servidor) su carga más rápido que el servidor.
Para verificar el progreso utilizando HttpClient, ajuste MultipartRequestEntity alrededor de uno que cuente los bytes que se envían. Wrapper está debajo:
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.httpclient.methods.RequestEntity;
public class CountingMultipartRequestEntity implements RequestEntity {
private final RequestEntity delegate;
private final ProgressListener listener;
public CountingMultipartRequestEntity(final RequestEntity entity,
final ProgressListener listener) {
super();
this.delegate = entity;
this.listener = listener;
}
public long getContentLength() {
return this.delegate.getContentLength();
}
public String getContentType() {
return this.delegate.getContentType();
}
public boolean isRepeatable() {
return this.delegate.isRepeatable();
}
public void writeRequest(final OutputStream out) throws IOException {
this.delegate.writeRequest(new CountingOutputStream(out, this.listener));
}
public static interface ProgressListener {
void transferred(long num);
}
public static class CountingOutputStream extends FilterOutputStream {
private final ProgressListener listener;
private long transferred;
public CountingOutputStream(final OutputStream out,
final ProgressListener listener) {
super(out);
this.listener = listener;
this.transferred = 0;
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
this.transferred += len;
this.listener.transferred(this.transferred);
}
public void write(int b) throws IOException {
out.write(b);
this.transferred++;
this.listener.transferred(this.transferred);
}
}
}
Luego implementa un ProgressListener que actualiza una barra de progreso.
Recuerde que la actualización de la barra de progreso no debe ejecutarse en el subproceso de envío de evento.
¿Podría dar un ejemplo de ProgressListener que actualizará los componentes de Swing – kilonet
por qué CountingMultipartRequestEntity debe ser envuelto alrededor de MultipartRequestEntity? – kilonet
Chicos, su respuesta es incorrecta. En muchos casos, esto contará dos veces todos los bytes enviados. FilterOutputStream # write (byte [], int, int) simplemente llama a FOS.write (byte) en un bucle, por lo que cuenta dos veces todos los bytes. Además, FOS recomienda cambiar este comportamiento ya que no es eficiente. Ver mi respuesta, donde guardo el flujo subyacente y llamo a su método de escritura (byte [], int, int). – Hamy
Apache común es una muy buena opción. Apache común le permite configurar las siguientes cosas.
- Configurar (archivo XML) el tamaño máximo del archivo de tamaño de archivo/carga
- Ruta de destino (dónde guardar el archivo cargado)
- puesto la temperatura. carpeta para intercambiar el archivo, de modo que la carga del archivo sea rápida.
¿Cuál de los componentes de Apache Commons? –
Sólo mi 2c pena:
Esto se basa apagado de la respuesta de Tuler (tiene un error en el momento de escritura). Lo modifiqué un poco, así que aquí está mi versión de Tuler y la respuesta de mmyers (parece que no puedo editar su respuesta). Quería intentar hacer esto un poco más limpio y más rápido.Además del error (que analizo en los comentarios sobre su respuesta), el gran problema que tengo con su versión es que crea un nuevo CountingOutputStream
con cada escritura. Esto puede ser muy costoso en términos de memoria: toneladas de asignaciones y recolección de basura. El problema más pequeño es que usa un delegado cuando simplemente podría expandir el MultipartEntity
. No estoy seguro de por qué eligieron eso, así que lo hice de una manera que estaba más familiarizado. Si alguien conoce las ventajas y desventajas de los dos enfoques, sería genial. Finalmente, el método FilterOutputStream # write (byte [], int, int) simplemente llama a FilterOutputStream # write (byte) en un bucle. El FOS documentation recomienda subclases que anulan este comportamiento y lo hacen más eficiente. La mejor manera de hacerlo aquí es dejar que OutputStream subyacente maneje la solicitud de escritura.
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
public class CountingMultiPartEntity extends MultipartEntity {
private UploadProgressListener listener_;
private CountingOutputStream outputStream_;
private OutputStream lastOutputStream_;
// the parameter is the same as the ProgressListener class in tuler's answer
public CountingMultiPartEntity(UploadProgressListener listener) {
super(HttpMultipartMode.BROWSER_COMPATIBLE);
listener_ = listener;
}
@Override
public void writeTo(OutputStream out) throws IOException {
// If we have yet to create the CountingOutputStream, or the
// OutputStream being passed in is different from the OutputStream used
// to create the current CountingOutputStream
if ((lastOutputStream_ == null) || (lastOutputStream_ != out)) {
lastOutputStream_ = out;
outputStream_ = new CountingOutputStream(out);
}
super.writeTo(outputStream_);
}
private class CountingOutputStream extends FilterOutputStream {
private long transferred = 0;
private OutputStream wrappedOutputStream_;
public CountingOutputStream(final OutputStream out) {
super(out);
wrappedOutputStream_ = out;
}
public void write(byte[] b, int off, int len) throws IOException {
wrappedOutputStream_.write(b,off,len);
++transferred;
listener_.transferred(transferred);
}
public void write(int b) throws IOException {
super.write(b);
}
}
}
Esto tiene muchos más problemas que el pequeño que el otro tenía. – ColinD
Un countingEntity más simple no dependería de un tipo de entidad específica sino que se extienden HttpEntityWrapped
:
package gr.phaistos.android.util;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;
public class CountingHttpEntity extends HttpEntityWrapper {
public static interface ProgressListener {
void transferred(long transferedBytes);
}
static class CountingOutputStream extends FilterOutputStream {
private final ProgressListener listener;
private long transferred;
CountingOutputStream(final OutputStream out, final ProgressListener listener) {
super(out);
this.listener = listener;
this.transferred = 0;
}
@Override
public void write(final byte[] b, final int off, final int len) throws IOException {
//// NO, double-counting, as super.write(byte[], int, int) delegates to write(int).
//super.write(b, off, len);
out.write(b, off, len);
this.transferred += len;
this.listener.transferred(this.transferred);
}
@Override
public void write(final int b) throws IOException {
out.write(b);
this.transferred++;
this.listener.transferred(this.transferred);
}
}
private final ProgressListener listener;
public CountingHttpEntity(final HttpEntity entity, final ProgressListener listener) {
super(entity);
this.listener = listener;
}
@Override
public void writeTo(final OutputStream out) throws IOException {
this.wrappedEntity.writeTo(out instanceof CountingOutputStream? out: new CountingOutputStream(out, this.listener));
}
}
¿cómo implementaría esto? ¿podría etiquetar si su respuesta :) –
como esto \t \t \t oyente ProgressListener = new ProgressListener() \t \t \t { \t \t \t \t @ Override \t \t \t \t public void transferido (NUM) \t \t \t \t { \t \t \t \t \t parentTask.publicPublishProgress (num); \t \t \t \t} \t \t \t}; \t \t \t StringEntity se = new StringEntity (XML); \t \t \t CountingHttpEntity ce = new CountingHttpEntity (se, listener); \t \t \t httppost.setEntity (ce); –
La cantidad de bytes devuelto por el oyente es diferente del tamaño del archivo original. Entonces, en lugar de tener transferred++
, lo modifiqué para que transferred=len
; esa es la longitud de la cantidad real de bytes que se escriben en la secuencia de salida. Y cuando puedo calcular la adición de los bytes totales transferida es igual a la real ContentLength
devuelto por CountingMultiPartEntity.this.getContentLength();
public void write(byte[] b, int off, int len) throws IOException {
wrappedOutputStream_.write(b,off,len);
transferred=len;
listener_.transferred(transferred);
}
De las otras respuestas que sólo puede anular los AbstractHttpEntity
niños de clase o implementaciones public void writeTo(OutputStream outstream)
método que está utilizando, si no lo hacen quiero crear una clase
Un ejemplo mediante una instancia FileEntity
:
FileEntity fileEntity = new FileEntity(new File("img.jpg")){
@Override
public void writeTo(OutputStream outstream) throws IOException {
super.writeTo(new BufferedOutputStream(outstream){
int writedBytes = 0;
@Override
public synchronized void write(byte[] b, int off, int len) throws IOException {
super.write(b, off, len);
writedBytes+=len;
System.out.println("wrote: "+writedBytes+"/"+getContentLength()); //Or anything you want [using other threads]
}
});
}
};
- 1. Subida directa a s3 con la barra de progreso usando php
- 2. oscilación con barra de progreso
- 3. Descarga asíncrona de archivos con barra de progreso
- 4. HTML5: carga de archivos AJAX con la barra de progreso
- 5. ¿Cómo descargar varios archivos en VB6 con barra de progreso?
- 6. barra de progreso Android con relleno
- 7. Superposición barra de progreso con jQuery
- 8. WPF: barra de progreso con duración indeterminada?
- 9. Barra de progreso con 2 indicadores
- 10. Barra de progreso y carga de archivos
- 11. Bonita barra de progreso en java
- 12. carga jQuery ajax con barra de progreso - sin flash
- 13. Barra de progreso vertical
- 14. Carga de archivos HTML5 con barras de progreso múltiples
- 15. Hacer pantalla de bienvenida con barra de progreso como Eclipse
- 16. Silverlight 4: la subida de archivos al servidor
- 17. barra de progreso circular
- 18. wxPython barra de progreso
- 19. barra de progreso de carga de archivos con clip en heroku
- 20. Carga de archivos con la barra de progreso en Asp.Net Mvc/jQuery?
- 21. Barra de progreso personalizado Android
- 22. ¿Cómo mostrar la barra de progreso con jQuery?
- 23. Subir archivo directamente a S3 con barra de progreso
- 24. Barra de título personalizado con progreso en Android
- 25. lista ¿Ver con la barra de progreso en cada elemento?
- 26. Barra de progreso para cargas de archivos iframe?
- 27. barra de progreso mientras la descarga de archivos IOS
- 28. Barra de progreso progresiva de Java del problema EDT
- 29. Barra de progreso para AVAssetExportSession
- 30. fábrica con el campo de subida carrierwave
Esto es sólo un comentario al margen, lo odio cuando las empresas utilizan los applets para proporcionar una mejor interfaz de subida y el de html. Creo que este es un problema del navegador web. No se puede confiar ciegamente en los applets que piden permiso, pero la mayoría de los usuarios lo dan de todos modos. Triste pero cierto. – Pyrolistical
@Pyrolistical Estoy de acuerdo, pero desafortunadamente, el soporte del navegador para cargar archivos es _simplemente horrible. Si agrega la necesidad/deseo de hacer cualquier procesamiento del lado del cliente en esos archivos, no tiene otra opción que no sea usar un applet o flash. – cdeszaq