203 Stimmen

Wie klont man einen InputStream?

Ich habe einen InputStream, die ich an eine Methode übergeben, um einige Verarbeitung zu tun. Ich werde denselben InputStream in einer anderen Methode verwenden, aber nach der ersten Verarbeitung wird der InputStream innerhalb der Methode geschlossen.

Wie kann ich den InputStream klonen, um ihn an die Methode zu senden, die ihn schließt? Gibt es eine andere Lösung?

EDIT: die Methoden, die den InputStream schließt, ist eine externe Methode aus einer Lib. Ich habe keine Kontrolle über das Schließen oder nicht.

private String getContent(HttpURLConnection con) {
    InputStream content = null;
    String charset = "";
    try {
        content = con.getInputStream();
        CloseShieldInputStream csContent = new CloseShieldInputStream(content);
        charset = getCharset(csContent);            
        return  IOUtils.toString(content,charset);
    } catch (Exception e) {
        System.out.println("Error downloading page: " + e);
        return null;
    }
}

private String getCharset(InputStream content) {
    try {
        Source parser = new Source(content);
        return parser.getEncoding();
    } catch (Exception e) {
        System.out.println("Error determining charset: " + e);
        return "UTF-8";
    }
}

6voto

Andrey E Punkte 826

UPD. Überprüfen Sie den vorherigen Kommentar. Es ist nicht genau das, was gefragt wurde.

Wenn Sie Folgendes verwenden apache.commons können Sie Ströme kopieren, indem Sie IOUtils .

Sie können folgenden Code verwenden:

InputStream = IOUtils.toBufferedInputStream(toCopy);

Hier ist das vollständige Beispiel, das für Ihre Situation geeignet ist:

public void cloneStream() throws IOException{
    InputStream toCopy=IOUtils.toInputStream("aaa");
    InputStream dest= null;
    dest=IOUtils.toBufferedInputStream(toCopy);
    toCopy.close();
    String result = new String(IOUtils.toByteArray(dest));
    System.out.println(result);
}

Dieser Code erfordert einige Abhängigkeiten:

MAVEN

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

GRADLE

'commons-io:commons-io:2.4'

Hier ist die DOC-Referenz für diese Methode:

Holt den gesamten Inhalt eines InputStreams und stellt dieselben Daten wie Ergebnis InputStream. Diese Methode ist nützlich, wenn,

Der Quell-InputStream ist langsam. Er ist mit Netzwerkressourcen verbunden, so dass wir können ihn nicht lange offen halten. Er ist mit einem Netzwerk-Timeout verbunden.

Sie können mehr über IOUtils hier: http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#toBufferedInputStream(java.io.InputStream)

3voto

Desmond Lua Punkte 5692

Nachfolgend finden Sie die Lösung mit Kotlin.

Sie können Ihren InputStream in ein ByteArray kopieren

val inputStream = ...

val byteOutputStream = ByteArrayOutputStream()
inputStream.use { input ->
    byteOutputStream.use { output ->
        input.copyTo(output)
    }
}

val byteInputStream = ByteArrayInputStream(byteOutputStream.toByteArray())

Wenn Sie die byteInputStream mehrere Male, rufen Sie byteInputStream.reset() bevor Sie erneut lesen.

https://code.luasoftware.com/tutorials/kotlin/how-to-clone-inputstream/

1voto

SpaceTrucker Punkte 12246

Das Klonen eines Eingabestroms ist unter Umständen keine gute Idee, da dies tiefe Kenntnisse über die Details des zu klonenden Eingabestroms erfordert. Eine Abhilfemaßnahme besteht darin, einen neuen Eingabestrom zu erstellen, der wieder von derselben Quelle liest.

Unter Verwendung einiger Java 8-Funktionen würde dies also so aussehen:

public class Foo {

    private Supplier<InputStream> inputStreamSupplier;

    public void bar() {
        procesDataThisWay(inputStreamSupplier.get());
        procesDataTheOtherWay(inputStreamSupplier.get());
    }

    private void procesDataThisWay(InputStream) {
        // ...
    }

    private void procesDataTheOtherWay(InputStream) {
        // ...
    }
}

Diese Methode hat den positiven Effekt, dass sie Code wiederverwendet, der bereits vorhanden ist - die Erstellung des Eingabestroms, gekapselt in inputStreamSupplier . Außerdem ist es nicht erforderlich, einen zweiten Codepfad für das Klonen des Streams zu pflegen.

Wenn jedoch das Lesen aus dem Stream teuer ist (weil es über eine Verbindung mit geringer Bandbreite erfolgt), dann verdoppelt diese Methode die Kosten. Dies könnte umgangen werden, indem ein spezieller Anbieter verwendet wird, der den Inhalt des Streams zunächst lokal speichert und eine InputStream für diese nun lokale Ressource.

0voto

vstrom coder Punkte 195

Die unten stehende Klasse sollte den Zweck erfüllen. Erstellen Sie einfach eine Instanz, rufen Sie die Methode "multiply" auf und geben Sie den Quell-Eingabestrom und die Anzahl der benötigten Duplikate an.

Wichtig: Sie müssen alle geklonten Streams gleichzeitig in separaten Threads verbrauchen.

package foo.bar;

import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class InputStreamMultiplier {
    protected static final int BUFFER_SIZE = 1024;
    private ExecutorService executorService = Executors.newCachedThreadPool();

    public InputStream[] multiply(final InputStream source, int count) throws IOException {
        PipedInputStream[] ins = new PipedInputStream[count];
        final PipedOutputStream[] outs = new PipedOutputStream[count];

        for (int i = 0; i < count; i++)
        {
            ins[i] = new PipedInputStream();
            outs[i] = new PipedOutputStream(ins[i]);
        }

        executorService.execute(new Runnable() {
            public void run() {
                try {
                    copy(source, outs);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        return ins;
    }

    protected void copy(final InputStream source, final PipedOutputStream[] outs) throws IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
        int n = 0;
        try {
            while (-1 != (n = source.read(buffer))) {
                //write each chunk to all output streams
                for (PipedOutputStream out : outs) {
                    out.write(buffer, 0, n);
                }
            }
        } finally {
            //close all output streams
            for (PipedOutputStream out : outs) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

0voto

Yash Punkte 8318

Die Verbesserung der @Anthony Accioly mit dem Beispiel.

InputStream : Klont die bytes-Stream und gibt die Anzahl der Kopien als Listensammlung an.

public static List<InputStream> multiplyBytes(InputStream input, int cloneCount) throws IOException {
    List<InputStream> copies = new ArrayList<InputStream>();

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    copy(input, baos);

    for (int i = 0; i < cloneCount; i++) {
        copies.add(new ByteArrayInputStream(baos.toByteArray()));
    }
    return copies;
}
// IOException - If reading the Reader or Writing into the Writer goes wrong.
public static void copy(Reader in, Writer out) throws IOException {
    try {
        char[] buffer = new char[1024];
        int nrOfBytes = -1;
        while ((nrOfBytes = in.read(buffer)) != -1) {
            out.write(buffer, 0, nrOfBytes);
        }
        out.flush();
    } finally {
        close(in);
        close(out);
    }
}

Leser : Klont die chars-Stream und gibt die Anzahl der Kopien als Listensammlung an.

public static List<Reader> multiplyChars(Reader reader, int cloneCOunt) throws IOException {
    List<Reader> copies = new ArrayList<Reader>();
    BufferedReader bufferedInput = new BufferedReader(reader);
    StringBuffer buffer = new StringBuffer();
    String delimiter = System.getProperty("line.separator");
    String line;
    while ((line = bufferedInput.readLine()) != null) {
        if (!buffer.toString().equals(""))
            buffer.append(delimiter);
        buffer.append(line);
    }
    close(bufferedInput);
    for (int i = 0; i < cloneCOunt; i++) {
        copies.add(new StringReader(buffer.toString()));
    }
    return copies;
}
public static void copy(InputStream in, OutputStream out) throws IOException {
    try {
        byte[] buffer = new byte[1024];
        int nrOfBytes = -1;
        while ((nrOfBytes = in.read(buffer)) != -1) {
            out.write(buffer, 0, nrOfBytes);
        }
        out.flush();
    } finally {
        close(in);
        close(out);
    }
}

Vollständiges Beispiel:

public class SampleTest {

    public static void main(String[] args) throws IOException {
        String filePath = "C:/Yash/StackoverflowSSL.cer";
        InputStream fileStream = new FileInputStream(new File(filePath) );

        List<InputStream> bytesCopy = multiplyBytes(fileStream, 3);
        for (Iterator<InputStream> iterator = bytesCopy.iterator(); iterator.hasNext();) {
            InputStream inputStream = (InputStream) iterator.next();
            System.out.println("Byte Stream:"+ inputStream.available()); // Byte Stream:1784
        }
        printInputStream(bytesCopy.get(0));

        //java.sql.Clob clob = ((Clob) getValue(sql)); - clob.getCharacterStream();
        Reader stringReader = new StringReader("StringReader that reads Characters from the specified string.");
        List<Reader> charsCopy = multiplyChars(stringReader, 3);
        for (Iterator<Reader> iterator = charsCopy.iterator(); iterator.hasNext();) {
            Reader reader = (Reader) iterator.next();
            System.out.println("Chars Stream:"+reader.read()); // Chars Stream:83
        }
        printReader(charsCopy.get(0));
    }

    // Reader, InputStream - Prints the contents of the reader to System.out.
    public static void printReader(Reader reader) throws IOException {
        BufferedReader br = new BufferedReader(reader);
        String s;
        while ((s = br.readLine()) != null) {
            System.out.println(s);
        }
    }
    public static void printInputStream(InputStream inputStream) throws IOException {
        printReader(new InputStreamReader(inputStream));
    }

    // Closes an opened resource, catching any exceptions.
    public static void close(Closeable resource) {
        if (resource != null) {
            try {
                resource.close();
            } catch (IOException e) {
                System.err.println(e);
            }
        }
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X