Bestimmen Sie die Größe eines InputStreams

78

Meine aktuelle Situation ist: Ich muss eine Datei lesen und den Inhalt einfügen InputStream. Danach muss ich den Inhalt von InputStreamin ein Byte-Array einfügen, das (soweit ich weiß) die Größe von erfordert InputStream. Irgendwelche Ideen?

Wie gewünscht, zeige ich den Eingabestream an, den ich aus einer hochgeladenen Datei erstelle

InputStream uploadedStream = null;
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
java.util.List items = upload.parseRequest(request);      
java.util.Iterator iter = items.iterator();

while (iter.hasNext()) {
    FileItem item = (FileItem) iter.next();
    if (!item.isFormField()) {
        uploadedStream = item.getInputStream();
        //CHANGE uploadedStreambyte = item.get()
    }
}

Der Antrag ist ein HttpServletRequestObjekt, das wie das ist FileItemFactoryund ServletFileUploadist aus dem Apache Commons Fileupload - Paket.

ChronoXIII
quelle

Antworten:

14

Ich wollte nur hinzufügen, Apache Commons IO hat Stream-Support-Dienstprogramme, um die Kopie durchzuführen. (Übrigens, was meinst du mit dem Platzieren der Datei in einem Inputstream? Kannst du uns deinen Code zeigen?)

Bearbeiten:

Okay, was möchten Sie mit dem Inhalt des Artikels machen? Es gibt eine, item.get() die das Ganze in einem Byte-Array zurückgibt .

Edit2

item.getSize()gibt die hochgeladene Dateigröße zurück .

akarnokd
quelle
Ich speichere die Datei derzeit in einem Blob-Feld in der Datenbank und sende sie als Binärstrom (Eingabe als Eingabestream). Jetzt benötige ich den Eingabestream in einem Byte-Array, da ich eine Signatur der Daten erstellen muss und die Funktion nur Byte benötigt Arrays.
ChronoXIII
1
item.get () netzt Ihnen das Byte-Array, wie ich bereits erwähnt habe. Machen Sie sich keine Sorgen über die Leistung und Größe, es sei denn, Sie arbeiten mit mehreren MB-Images.
Akarnokd
Dies könnte der Fall sein, da das Bild von einem Benutzer hochgeladen wird und ich anscheinend keine Möglichkeit finde, Bilder auf der Serverseite automatisch zu trimmen. :(
ChronoXIII
Was meinst du mit automatischem Zuschneiden von Bildern? get () gibt Ihnen die gesamte hochgeladene Datei (Bild) als Byte []. Dann verwenden Sie es für jedes OutputStream.write (), wickeln es erneut in ByteArrayInputStream usw. ein
akarnokd
Ich habe die Lösung für diesen Beitrag geändert, da die Antwort für mein aktuelles Setup genauer abgestimmt wurde
ChronoXIII
60

Dies ist ein WIRKLICH alter Thread, aber es war immer noch das erste, was auftauchte, als ich das Problem googelte. Also wollte ich nur folgendes hinzufügen:

InputStream inputStream = conn.getInputStream();
int length = inputStream.available();

Hat für mich gearbeitet. Und VIEL einfacher als die anderen Antworten hier.

Warnung Diese Lösung liefert keine zuverlässigen Ergebnisse hinsichtlich der Gesamtgröße eines Streams. Außer aus dem JavaDoc:

Beachten Sie, dass einige Implementierungen von {@code InputStream} * die Gesamtzahl der Bytes im Stream zurückgeben, viele jedoch nicht.

WB Reed
quelle
81
Ich denke nicht, dass das richtig ist. Aus den Javadocs: "Beachten Sie, dass einige Implementierungen von InputStream zwar die Gesamtzahl der Bytes im Stream zurückgeben, viele jedoch nicht. Es ist niemals korrekt, den Rückgabewert dieser Methode zu verwenden, um einen Puffer zuzuweisen, der alle Daten in diesem enthalten soll Strom." Möglicherweise hat es auf Ihrer VM funktioniert, aber möglicherweise nicht auf der einer anderen. docs.oracle.com/javase/7/docs/api/java/io/…
Marvo
3
Oh psych. Schöner Fang! Ich denke, dieser Trick ist nicht gut für Code, der portabel sein muss. Ich habe für ein Schulprojekt verwendet, also hat es für mich funktioniert. Vielen Dank, gut zu wissen für die Zukunft!
WB Reed
4
Das ist perfekt, wenn Sie alle Daten wie in einem ByteArrayInputStream im Speicher haben.
Stapler
9
Es ist falsch! In der Dokumentation zur available()Methode "Beachten Sie, dass einige Implementierungen von InputStream zwar die Gesamtzahl der Bytes im Stream zurückgeben, viele jedoch nicht. Es ist niemals korrekt, den Rückgabewert dieser Methode zum Zuweisen eines Puffers zu verwenden, der alle enthalten soll Daten in diesem Stream. "
GVillani82
4
Die Antwort ist irreführend: Was ist mit Android-Dokumenten ? Es wird klar gesagt: "Beachten Sie, dass diese Methode eine so schwache Garantie bietet, dass sie in der Praxis nicht sehr nützlich ist. "
Ksenia
37

Ich würde in einen ByteArrayOutputStream einlesen und dann toByteArray () aufrufen , um das resultierende Byte-Array zu erhalten. Sie müssen die Größe nicht im Voraus definieren (obwohl dies möglicherweise eine Optimierung ist, wenn Sie sie kennen . In vielen Fällen werden Sie dies nicht tun ).

Brian Agnew
quelle
Ich habe anscheinend festgestellt, dass Inputstream eine toString () -Methode hat, und dann kann ich einfach getBytes () aufrufen, um ein Byte-Array aus der Zeichenfolge zu erstellen. Ich frage mich, ob dies zu Leistungsproblemen führt.
ChronoXIII
Sie müssen bei der Konvertierung von Bytes / Zeichen vorsichtig sein. Ist das ursprünglich ein Byte-Stream? Wenn es Zeichen enthält, wie werden sie codiert usw. Wenn Sie diese über eine Netzwerkverbindung erhalten, würde ich vermuten, dass dies Ihr Hauptleistungsengpass ist, und ich würde mir keine Sorgen über den Konvertierungsaufwand machen
Brian Agnew
Ich lese derzeit den Eingabestream mit dem Bild in eine Datenbank als Binärstream. Dies scheint gut zu funktionieren, da ich die Datei nach den
Worten
2
Ja. Sie erhalten das vollständige Raw-Byte-Array, keine Konvertierung, keine Probleme.
Akarnokd
1
Ist dieser Speicher nicht wirklich ineffizient, wenn Sie nur die Größe wünschen?
CDMckay
19

Sie können die Datenmenge in einem Stream nicht bestimmen, ohne sie zu lesen. Sie können jedoch nach der Größe einer Datei fragen:

http://java.sun.com/javase/6/docs/api/java/io/File.html#length ()

Wenn dies nicht möglich ist, können Sie die aus dem Eingabestream gelesenen Bytes in einen ByteArrayOutputStream schreiben, der nach Bedarf wächst.

Andrew Duffy
quelle
In meinem Szenario enthält der Inputstream eine hochgeladene Datei aus einem HTML-Formular. Ich kann die Dateigröße nicht ermitteln, da ich die Datei nicht von der Festplatte lade.
ChronoXIII
1
Wenn Ihr Eingabestream mark () unterstützt, können Sie ihn am Anfang markieren und einfach vollständig durchlesen - dann reset () und mit der Verarbeitung beginnen.
Akarnokd
1
Die Datei ist ein Bild (möglicherweise groß). Wenn Sie den Stream also zweimal durchlesen, kann dies zu Leistungsproblemen führen, nicht wahr?
ChronoXIII
Versuch es. Wenn es sehr langsam ist, haben Sie Leistungsprobleme. Sonst nicht. So einfach ist das.
Bombe
@ ChronoXIII: Stimmt. Aus diesem Grund habe ich nach einem kleinen Codebeispiel gefragt, damit wir Ihr Szenario sehen können. Wenn sich Ihr Bild bereits im Speicher befindet (dank Datei-Upload oder Ähnlichem), werden weitere Optionen geöffnet.
Akarnokd
8

Für InputStream

org.apache.commons.io.IoUtils.toByteArray(inputStream).length()

Für optionales <MultipartFile>

Stream.of(multipartFile.get()).mapToLong(file->file.getSize()).findFirst().getAsLong()
Amstegraf
quelle
1
Ich kann IoUtils nirgendwo finden. Ich denke du meinst org.apache.commons.io.IOUtils,
ostmond
IOUtils.toByteArray (inputStream) .length hat bei mir nicht funktioniert.
dev4life
Ja. Es funktioniert nicht mit IOUtils. Nicht sicher, warum diese Methode ist und wie dies nützlich sein kann.
UM1979
Es wird ein Byte-Array zurückgegeben, das die Methode length () hat. Ich habe nur vergessen, die Paranthesis hinzuzufügen
amstegraf
4

Sie können die Größe von InputStream mit getBytes (inputStream) von Utils.java ermitteln. Überprüfen Sie diesen folgenden Link

Holen Sie sich Bytes von Inputstream

Gnanam R.
quelle
Sollte dies nicht auch eine richtige Antwort sein? Probleme mit dieser Lösung?
Arlyn
2
Wenn Sie vorhatten, Ihren Eingabestream zu verwenden, wurde er bereits gelesen.
Amber
1

Wenn Sie sich explizit mit einem ByteArrayInputStreamdann entgegen einigen Kommentaren auf dieser Seite befassen , können Sie die .available()Funktion verwenden, um die Größe zu ermitteln. Sie müssen es nur tun, bevor Sie anfangen, daraus zu lesen.

Aus den JavaDocs:

Gibt die Anzahl der verbleibenden Bytes zurück, die von diesem Eingabestream gelesen (oder übersprungen) werden können. Der zurückgegebene Wert ist count - pos. Dies ist die Anzahl der Bytes, die noch aus dem Eingabepuffer gelesen werden müssen.

https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#available ()

Sverrir Sigmundarson
quelle
0

Wenn Sie wissen, dass InputStreames sich um ein FileInputStreamoder ein handelt ByteArrayInputStream, können Sie eine kleine Reflexion verwenden, um die Stream-Größe zu ermitteln, ohne den gesamten Inhalt zu lesen . Hier ist eine Beispielmethode:

static long getInputLength(InputStream inputStream) {
    try {
        if (inputStream instanceof FilterInputStream) {
            FilterInputStream filtered = (FilterInputStream)inputStream;
            Field field = FilterInputStream.class.getDeclaredField("in");
            field.setAccessible(true);
            InputStream internal = (InputStream) field.get(filtered);
            return getInputLength(internal);
        } else if (inputStream instanceof ByteArrayInputStream) {
            ByteArrayInputStream wrapper = (ByteArrayInputStream)inputStream;
            Field field = ByteArrayInputStream.class.getDeclaredField("buf");
            field.setAccessible(true);
            byte[] buffer = (byte[])field.get(wrapper);
            return buffer.length;
        } else if (inputStream instanceof FileInputStream) {
            FileInputStream fileStream = (FileInputStream)inputStream;
            return fileStream.getChannel().size();
        }
    } catch (NoSuchFieldException | IllegalAccessException | IOException exception) {
        // Ignore all errors and just return -1.
    }
    return -1;
}

Ich bin mir sicher, dass dies erweitert werden könnte, um zusätzliche Eingabestreams zu unterstützen.

Travis Parks
quelle
Wenn Sie es sich leisten können, den inputStream neu zu erstellen und darauf zu warten, können Sie alles lesen, um seine Größe als Fallback für all diese zu erhalten
Android-Entwickler
-1

Verwenden Sie diese Methode, Sie müssen nur den InputStream übergeben

public String readIt(InputStream is) {
    if (is != null) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);

        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        is.close();
        return sb.toString();
    }
    return "error: ";
}
Carlos.V
quelle
1
-1, dies setzt voraus, dass InputStreames sich immer um einen String handelt (nicht erforderlich, da es sich möglicherweise um Binärdaten handelt), und in jedem Fall wird nicht die Größe des Streams zurückgegeben, nach der die Frage gestellt wurde. Darüber hinaus werden \nden Daten zusätzliche Bytes ( ) hinzugefügt, sodass sb.length()auch die Daten ungenau sind.
Vicky Chijwani
Ok, ich verstehe, das ist also nützlich, wenn Sie wissen, dass Sie einen StringStream erwarten . \nwird wirklich benötigt, weil Sie der empfangenen Eingabe ein Format geben müssen. Ich möchte keine lange Chorizo String, also zählt auch diese \n.
Carlos.V
-1
    try {
        InputStream connInputStream = connection.getInputStream();
    } catch (IOException e) {
        e.printStackTrace();
    }

    int size = connInputStream.available();

int available () Gibt eine Schätzung der Anzahl der Bytes zurück, die aus diesem Eingabestream gelesen (oder übersprungen) werden können, ohne beim nächsten Aufruf einer Methode für diesen Eingabestream blockiert zu werden. Der nächste Aufruf kann der gleiche Thread oder ein anderer Thread sein. Ein einzelnes Lesen oder Überspringen dieser vielen Bytes blockiert nicht, kann jedoch weniger Bytes lesen oder überspringen.

InputStream - Android SDK | Android-Entwickler

Ashnet
quelle
Dies ist ein Fehler, so dass ich festgestellt habe, dass die verfügbare () Funktion nur die aktive Datengröße und nicht die Länge des Lochstroms zurückgibt.
Ashnet