Cómo convertir InputStream a archivo virtual

81

Tengo un método que espera que la variable de entrada sea del tipo java.io.File, pero lo que obtengo es solo InputStream. Además, no puedo cambiar la firma del método.

¿Cómo puedo convertir InputStream en un tipo de archivo sin tener que escribir el archivo en el sistema de archivos?

RAM
fuente
¿Es esta una función incorporada? o es una función personalizada?
Richard J. Ross III
2
@Richard: "No puedo cambiar la firma del método".
BalusC
¿Por qué exactamente necesitas un Fileobjeto en lugar de InputStream?
Poindexter
2
No puedo usar InputStream porque la API que estoy usando mandatos Archivo
Ram
Me parece que alguien diseñó una API rota que solo acepta archivos en lugar de InputStreams, y ahora tienes que usar esta API
Mike76

Respuestas:

121

Algo como esto debería funcionar. Tenga en cuenta que para simplificar, he usado una función de Java 7 (intente bloquear con recurso que se puede cerrar) e IOUtils de Apache commons-io. Si no puede usarlos, será un poco más largo, pero la misma idea.

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class StreamUtil {

    public static final String PREFIX = "stream2file";
    public static final String SUFFIX = ".tmp";

    public static File stream2file (InputStream in) throws IOException {
        final File tempFile = File.createTempFile(PREFIX, SUFFIX);
        tempFile.deleteOnExit();
        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            IOUtils.copy(in, out);
        }
        return tempFile;
    }

}
cobbzilla
fuente
8
¿No es createTempFile realmente escribe un archivo real, que puede ver en el sistema de archivos?
desarrollador de Android
es técnicamente correcto. usando el código anterior, el archivo temporal existirá hasta que el programa salga o sea eliminado por el programa.
cobbzilla
Los documentos de deleteOnSalir dicen que no debes confiar en que funcione (y creo que en realidad ni siquiera hace nada): developer.android.com/reference/java/io/… . Además, si sabe cómo transmitir el audio a la reproducción, sin ningún archivo, escríbalo aquí: stackoverflow.com/q/36552381/878126
desarrollador de Android
4
En términos generales, prefiero que la aplicación elimine el archivo temporal cuando tenga sentido hacerlo. Lo uso deleteOnExitcomo un control adicional de cordura, nunca confío incondicionalmente en él. Sé que en ciertas situaciones ( kill -9la JVM, por ejemplo) nunca se llamará a los ganchos de cierre que realizan la eliminación.
cobbzilla
Si está usando esto en Android, agréguelo implementation 'org.apache.directory.studio:org.apache.commons.io:2.4'a gradle.
LordParsley
30

No puedes. El flujo de entrada es solo un flujo genérico de datos y no hay garantía de que realmente se origine en un archivo. Si alguien crea un InputStream a partir de la lectura de un servicio web o simplemente convierte un String en un InputStream, no habría forma de vincularlo a un archivo. Entonces, lo único que puede hacer es escribir datos de la secuencia en un archivo temporal (por ejemplo, usando el método File.createTempFile) e introducir este archivo en su método.

Jan Thomä
fuente
7
De hecho, File#createTempFile()es realmente tu mejor opción.
BalusC
7
Consulte también File#deleteOnExit(), lo que hace que la JVM intente eliminar el archivo automáticamente cuando sale de la JVM. Por supuesto, es mejor eliminar el archivo temporal de forma manual e inmediata, una vez que sepa que el archivo ya no es necesario y ya no está en uso. Pero en un mundo imperfecto a veces se necesitan soluciones imperfectas.
Mike Clark