2017-02-18 3 views
0

Ich habe einen kleinen Server geschrieben, der einen Datenblock in Form einer io.Reader empfängt, einen Header hinzufügt und das Ergebnis zurück zum Aufrufer überträgt.Präfix zu io.Reader hinzufügen

Meine Implementierung ist nicht besonders effizient, da ich die In-Memory-Daten des Blobs puffern, so dass ich die Länge des Blobs berechnen kann, die Teil des Headers sein muss.

Ich habe einige Beispiele von io.Pipe() mit io.TeeReader gesehen, aber sie sind mehr für das Teilen eines io.Reader in zwei, und schreiben sie weg parallel.

Die Blobs ich bin den Umgang sind um 100 KB, also nicht sehr groß, aber wenn mein Server ausgelastet wird, ist Speicher schnell ein Problem ...

Irgendwelche Ideen

gehen zu werden?

func addHeader(in io.Reader) (out io.Reader, err error) { 
    buf := new(bytes.Buffer) 
    if _, err = io.Copy(buf, in); err != nil { 
     return 
    } 

    header := bytes.NewReader([]byte(fmt.Sprintf("header:%d", buf.Len()))) 

    return io.MultiReader(header, buf), nil 
} 

Ich schätze, es ist keine gute Idee, Schnittstellen von Funktionen zurückzukehren, aber dieser Code ist nicht eine API bestimmt werden, so dass ich nicht zu sehr mit diesem Bit.

Antwort

0

Im Allgemeinen kann die Länge der Daten in einem io.Reader nur bis EOF gelesen werden. Es gibt Möglichkeiten, die Länge der Daten für bestimmte Typen zu bestimmen.

func addHeader(in io.Reader) (out io.Reader, err error) { 
    n := 0 
    switch v := in.(type) { 
    case *bytes.Buffer: 
    n = v.Len() 
    case *bytes.Reader: 
    n = v.Len() 
    case *strings.Reader: 
    n = v.Len() 
    case io.Seeker: 
    cur, err := v.Seek(0, 1) 
    if err != nil { 
     return nil, err 
    } 
    end, err := v.Seek(0, 2) 
    if err != nil { 
     return nil, err 
    } 
    _, err = v.Seek(cur, 0) 
    if err != nil { 
     return nil, err 
    } 
    n = int(end - cur) 
    default: 
    var buf bytes.Buffer 
    if _, err := buf.ReadFrom(in); err != nil { 
     return nil, err 
    } 
    n = buf.Len() 
    in = &buf 
    } 
    header := strings.NewReader(fmt.Sprintf("header:%d", n)) 
    return io.MultiReader(header, in), nil 
} 

Dies ist ähnlich wie die net/http Paket determines the content length of the request body.

+0

Danke für die Antwort, Cerise. Es ist ein io.ReadCloser unter der Decke, also muss ich es wohl puffern. Prost! – Rob

+0

@Rob io.ReadCloser ist ein Schnittstellentyp. Der konkrete Typ ist etwas anderes. Probieren Sie 'fmt.Println ("% T ", in)' aus, um zu sehen, was der konkrete Typ ist. Vielleicht wird es einer der Typen sein, die in meiner Antwort aufgelistet sind, oder eine, von der Sie die Länge extrahieren können, ohne sie zu lesen. –

+0

Ah ja, ich werde die zugrunde liegende Implementierung überprüfen und sehen, ob ich die Länge extrahieren kann. Vielen Dank! – Rob

Verwandte Themen