Hola:
La primera opción es la más ineficiente. Siempre es más eficiente leer/escribir muchos bytes en disco de golpe que de uno en uno. Podrías hacerla más eficiente usando métodos de leer/escribir arrays de byte[] de tamaños más o menos grande. Las clases BufferedInputStream, BufferedReader, o BufferedOutputStream, BufferedWriter se encargan automáticamente de coger bloques de bytes enteros de disco en memoria y dártelos según los pidas.
Entre las otras opciones, no podría decirte cual es más eficiente, puesto que depende de cómo la hayan implementado por debajo (transfer, copy de windows, Files.copy), pero imagino que cualquiera de ellas vale, si nos fiamos de los que lo han implementado por debajo.
Otro detalle a tener en cuenta. Si son muuuuchos ficheros, windows es más eficiente haciendo un zip con todos ellos y transfiriendo ese único fichero que hacer la transferencia de los ficheros por separado. Puedes probarlo rápidamente sin hacer ningún programa, basta con hacer la prueba arrastrando los ficheros (bien el zip, bien el directorio que contenga la multitud de ficheros) en el explorador de windows y ver el resultado. Tendrías que ver lo que cuesta hacer el zip, pero según cuántos ficheros sean, en general compensa (nunca lo he hecho con 80TB, no sé que puede tardar un zip de eso o si lo aguanta siquiera, pero puedes probar a hacer varios zip más pequeños en vez de uno grande).
Saludos.
Esto me ayuda muchisimo! Lo aprecio mucho, voy a investigar y hacer algunas pruebas con lo que me dijiste.
Si me topo con alguna duda puede que te envie algun mesaje, espero que no te moleste.
Gracias!