Como obtener la tasa de transferencia en un InputStream?

Hola =) Estoy haciendo un pequeño programa para juguetear pero no he podido obtener lo que busco.

El programa es basicamente este:

 
Sin embargo este es el resultado:

Como se puede ver no tengo ni idea de donde la estoy regando, agradeceria cualquier informacion/tip/sugerencia ;)

Lo que me causa mas confusion es la tasa de transferencia(Ts) ya que casi todos sus resultados son negativos y muy altos.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Estás restando la hora

Estás restando la hora anterior a la más reciente, es al revés, el tiempo más reciente siempre va a tener más milisegundos que un tiempo anterior.

Sobre la forma de hacer la descarga, tengo la impresión que se puede mejorar si separas la acción de reportar de la acción de bajar, finalmente hacer las operaciones aritméticas e imprimir a pantalla también toman tiempo, pero supongo que en este caso sirve bien.

Extra: puedes usar printf para formatear la salida más fácilmente. En el try w/resources puedes poner más de un recurso para que él lo cierre. El MalformerURL es subclase de IOException, puedes usar un solo catch. Y finalmente puedes usar espacios entre lineas para dar formato código y hacerlo más legible ( yo uso un espacio para separar bloques de código relacionados y alineo las asignaciones nomás porque si )

Ahí va con los cambios.

 

Imagen de ezamudio

Errores

No estás tomando tiempo de la primera lectura, solamente de la segunda en adelante. Como ya dijo Oscar, estás restando t0 a t1 y debe ser alrevés.

La conversión a kilobytes o cualquier otra unidad la deberías hacer al final. Todos los programas miden en bytes por segundo y de ahí convierten.

Y deberías hacer el buffer más grande. Un buffer tan chico puede causar que te tardes más en leer, porque estás haciendo varias lecturas de un buffer de red a nivel sistema operativo. 16384 bytes o tal vez hasta 65536 bytes es mejor (buffers chicos sirven del lado del server para no acabarse la memoria pero del lado del cliente no hay razón para no crear un buffer de 64KB a menos que este código lo pienses ejecutar en un telefonito con JavaME y aún así podrías usar unos 8 o de menos 4KB).

Pero esto que estás haciendo no es muy exacto... o bueno, se puede considerar que de hecho es tan exacto que no es útil. La manera de obtener un estimado más estable (sin tantas variaciones entre lecturas) requiere que vayas guardando todos esos tiempos y bytes leídos. Por ejemplo crear una clase   que guarde el tiempo en milis o nanos, y el número de bytes leídos en ese tiempo, y luego sacar un promedio con todas las muestras que llevas hasta el momento. Y sobre todo eso te servirá para determinar cuánto tiempo te falta para bajar y no tener el problema de estimaciones de tiempo de Windows.

Imagen de Jose Manuel

Una? duda rapida?

Gracias por contestar, ¡Siganme los buenos¡, ¡Ah no¡ :) siganme brindando su ayuda por favor.
He perdido mi conexion a internet y estoy contestando de emergencia, mientras se arreglan los problemas, me gustaria que me ayudaran con la logica.

No se porque me equivoque con la estimacion del tiempo de lectura mediante nanoTime(); jeje error de novato... u_u

Oscar podrias aclararme unas dudas?
@OscarRyz dice:

Sobre la forma de hacer la descarga, tengo la impresión que se puede mejorar si separas la acción de reportar de la acción de bajar, finalmente hacer las operaciones aritméticas e imprimir a pantalla también toman tiempo, pero supongo que en este caso sirve bien.

Que quieres decir con eso?, algun ejemplo para este dummie? Sobre todo eso de separar la accion de bajar con la de reportar. Es esto parecido a lo que menciona @ezamudio en su comentario sobre la clase Muestra o otra cosa?

Sobre el extra: Me interesa que los valores puedan ser obtenidos de manera simple y si es posible facil (aunque aqui esta mi problema). Por los demas consejos, gracias. Los tomare en cuenta, siempre me falla el formatear codigo.

@ezamudio dice:

La conversión a kilobytes o cualquier otra unidad la deberías hacer al final. Todos los programas miden en bytes por segundo y de ahí convierten.

La conversion la realizo al final, cuando imprimo KB/S o a que forma te refieres?

@ezamudio dice:

Y deberías hacer el buffer más grande. Un buffer tan chico puede causar que te tardes más en leer, porque estás haciendo varias lecturas de un buffer de red a nivel sistema operativo. 16384 bytes o tal vez hasta 65536 bytes es mejor (buffers chicos sirven del lado del server para no acabarse la memoria pero del lado del cliente no hay razón para no crear un buffer de 64KB a menos que este código lo pienses ejecutar en un telefonito con JavaME y aún así podrías usar unos 8 o de menos 4KB).

Ok, no se mucho sobre la practica y la teoria me falsea a veces. Segun yo al leer del input obtenemos una cantidad de bytes del stream, ya sea del mismo tamaño que del buffer o cercano a el, aunque lo que crei ver en mi programa es que casi nunca es del mismo tamaño. Asi es que por eso en un programa de red realizar tantas peticiones a el sistema servidor para que solo lea una pequeña cantidad de bytes no es eficiente. Aunque no entiendo, si el buffer es asignado en cada lectura y los flujos cerrados ¿como puede llegar a acabar la memoria?

Y si te entendi en lo primero..., ¿Como saber que tamaño de buffer usar, ya que no siempre usa todo el espacio disponible?

@ezamudio dice:

Pero esto que estás haciendo no es muy exacto... o bueno, se puede considerar que de hecho es tan exacto que no es útil. La manera de obtener un estimado más estable (sin tantas variaciones entre lecturas) requiere que vayas guardando todos esos tiempos y bytes leídos. Por ejemplo crear una clase Muestra que guarde el tiempo en milis o nanos, y el número de bytes leídos en ese tiempo, y luego sacar un promedio con todas las muestras que llevas hasta el momento. Y sobre todo eso te servirá para determinar cuánto tiempo te falta para bajar y no tener el problema de estimaciones de tiempo de Windows.

Espere, para que no quede duda: Lo que intento hacer: Descargar un enlace URL en mi PC, obtener la velocidad con la que descargo el archivo (a eso le llamo Tasa de transferencia), la cantidad que lleva descargada y el tiempo estimado. La formula de velocidad de transferencia segun yo es:
 

Para la cantidad descargada se que puedo usar un acumulador:
 
Probablemente debi comenzar desde alli... perdon. Como decia Sr. @ezamudio, usted piensa que estoy obteniendo bien la velocidad de transferencia de datos pero es tan exacta que son poco utiles para el end-user y ademas existen demasiadas variaciones en las lecturas. Por lo que recomienda que haga un muestreo/promedio? Podria ayudarme con pseudo codigo?

Gracias por leer, si son preguntas muy basicas o tontas, seria excelente que me recomendaran temas, lecturas, libros. Cualquier cosa que me ayude a formarme como mejor desarrollador.
Saludos.

Imagen de ezamudio

A ver

Lo que digo es que NO te vas a acabar la memoria usando un buffer más grande, por lo tanto, deberías usar un buffer más grande. Si lo creas de 16KB por ejemplo y solamente lees 500 bytes pues no pasa nada, lo leíste todo "de un jalón". Es mejor hacer lecturas a un buffer grande, en menos iteraciones, que más iteraciones leyendo a un buffer chico. Ya no sé qué tan más claro puedo ser al respecto.

Y la conversión a kb/s sí la estás haciendo en cada iteración, no al final. También estás imprimiendo la tasa de transferencia en cada iteración (cada lectura). Lo que dice Oscar es respecto a imprimir ese mensaje. Se llama separation of concerns; si tu componente descarga un archivo, que haga eso y ya, no tiene que estar imprimiendo. Qué pasa si lo quieres usar en una aplicación Swing o JavaFX? No sirve de nada el println. Lo que debe tener es un listener que reciba notificaciones cada que se ha leído algo, para que pueda actualizar la manera en que reporta. Esto no es otra cosa más que definir una interfaz que el componente utiliza y que alguien más debe implementar para ser un listener:

 

en tu código quitas todas esas conversiones y el println y en vez de eso simplemente:

 

Y bueno tienes que tomar tiempo antes de hacer la primera lectura, y nuevamente después de la última lectura, y en tu bloque finally invocar el otro método:

 

y ya por fuera puedes tener algo como esto:

 

Obvio tienes que reorganizar tu código existente en un componente reutilizable y al final puedes tener un main más o menos así:

 

y así luego será más fácil mejorar esos cálculos porque ya ni siquiera tienes que tocar el componente que hace la descarga; solamente el listener.

Para el manejo de los streams deberías tener un try-with-resources dentro del try que ya tienes, puro try-finally sin catch, para que esos streams (el de lectura del socket y el de escritura del archivo) se cierren siempre. El método download debería ya recibir un URL, no un String, y así puedes simplemente hacer el try externo también que sea try-with-resources para obtener la conexión y que se cierre siempre.

Imagen de Jose Manuel

Creo que hay voy...

Primero trate de hacer las cosas tal y como me dijo, espero haber acertado en algunas.

Mi interface
 
Mi implementacion de la interfaz
 
Mi clase Download
 
Mi main
 
Es todo lo que llevo pero si obtenemos la salida el resultado es:

Aun no estoy seguro de que estoy aplicando bien la logica... y tampoco las formulas.
Cualquier consejo es bienvenido

Imagen de ezamudio

catch interno

Quita el catch interno, solamente debe ser try-finally:

 

No necesitas hacer nada porque ese try asegura que se cierren los streams al finalizar, pase lo que pase.

Creo que te estás revolviendo un poco con las variables de tiempos. No sé para qué sumas una con otra en el ciclo, pero bueno eso ya es algo bastante simple que seguramente puedes arreglar tú.

Imagen de Jose Manuel

te odio System.nanoTime()

Y de nuevo me equivoque en el nanoTime(); XD

Lo que queria hacer era obtener el tiempo de la primera lectura y trataba de agregar ese tiempo. Pero no se me ocurrio como hacerlo sin que afectara en el ciclo. Jajaja usted me dice que es bastante simple pero no se me ocurre nada por ahora.
Si me entero de algo posteo sino ya quedaria el programa o le haria algunos pequeños cambios.

Imagen de Jose Manuel

He realizado unos pequeños

He realizado unos pequeños pero vistosos cambios
Ahora el metodo downloadProgress de la implementacion de la interfaz imprime nuevos datos

 
Dando;

EDIT:
Agradeceria cualquier ayuda para determinar correctamente la tasa de transferencia ya que es lo unico que me falta. Saludos.