2012-01-05 16 views
39

Estoy en el proceso de escribir un servicio WCF que permitirá que un sitio web ASP.Net recupere archivos (basado en this article). Mi problema es que cuando devuelvo la transmisión, está en blanco.Devolución de una secuencia desde File.OpenRead()

Por simplicidad, he aislado el código en una simple aplicación de Windows Forms para tratar de encontrar cuál es el problema con la devolución de una corriente y este es el código:

private Stream TestStream() 
    { 
     Stream fs = File.OpenRead(@"c:\testdocument.docx"); 
     return fs; 
    } 

    // This method converts the filestream into a byte array so that when it is 
    // used in my ASP.Net project the file can be sent using response.Write 
    private void Test() 
    {    
     System.IO.MemoryStream data = new System.IO.MemoryStream(); 
     System.IO.Stream str = TestStream(); 

     str.CopyTo(data); 
     byte[] buf = new byte[data.Length]; 
     data.Read(buf, 0, buf.Length);      
    } 

El resultado de este código es que buf tiene 12,587 bytes de longitud (la longitud correcta del archivo) pero solo contiene 0.

El documento de Word se abre sin problemas si lo intento, ¿me falta algo obvio?

+1

¿Se está ejecutando como administrador? Intente extraer el documento de 'Mis documentos' u otra carpeta que no sea root. – keyboardP

+1

@keyboard - buen consejo pero produciría una excepción, no '0's y longitud correcta. –

+0

@HenkHolterman - Ah sí, eso es cierto. – keyboardP

Respuesta

31

se le olvidó a buscar:

str.CopyTo(data); 
data.Seek(0, SeekOrigin.Begin); // <-- missing line 
byte[] buf = new byte[data.Length]; 
data.Read(buf, 0, buf.Length); 
+0

Gracias Ken, eso funcionó como un regalo. – GrandMasterFlush

+0

¿qué ocurre si no está permitido buscar? –

1

trate de cambiar su código para esto:

private void Test() 
{    
    System.IO.MemoryStream data = new System.IO.MemoryStream(TestStream()); 

    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length);      
} 
3

Usted necesita

str.CopyTo(data); 
    data.Position = 0; // reset to beginning 
    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length); 

Y puesto que su método Test() está imitando el cliente debería a Close() o Dispose() el str S Tream. Y el memoryStream también, solo fuera del principal.

+0

Gracias Henk, funcionó bien. El código WCF cerrará/eliminará las transmisiones en consecuencia, dejé esto en la aplicación de prueba. – GrandMasterFlush

+0

Lo reuní, pero eso lo convierte en una aplicación de prueba incompleta. –

+0

De acuerdo, pero la aplicación fue solo para probar/depurar el problema, no un arnés de prueba ni nada relacionado con ninguna prueba formal. Fue más fácil para mí portar el código en una aplicación simple y luego probar y depurar el servicio WCF en su servidor. – GrandMasterFlush

12

Opciones:

  • Uso data.Seek como sugiere ken2k
  • Utilice el algo más simple Position propiedad:

    data.Position = 0; 
    
  • Uso del ToArray llamada en MemoryStream para hacer su vida más simple para empezar con:

    byte[] buf = data.ToArray(); 
    

La tercera opción sería mi enfoque preferido.

en cuenta que debe tener una declaración using para cerrar el flujo de archivos de forma automática (y opcionalmente para el MemoryStream), y me gustaría añadir una directiva using para System.IO para hacer su código más limpio:

byte[] buf; 
using (MemoryStream data = new MemoryStream()) 
{ 
    using (Stream file = TestStream()) 
    { 
     file.CopyTo(data); 
     buf = data.ToArray(); 
    } 
} 

// Use buf 

Usted también puede querer crear un método de extensión en Stream para hacer esto por usted en un solo lugar, por ejemplo

public static byte[] CopyToArray(this Stream input) 
{ 
    using (MemoryStream memoryStream = new MemoryStream()) 
    { 
     input.CopyTo(memoryStream); 
     return memoryStream.ToArray(); 
    } 
} 

Tenga en cuenta que este no cerrar el flujo de entrada.

+0

Gracias Jon, esa es una forma mucho mejor de hacerlo. El servicio WCF utiliza las instrucciones de uso, las había omitido del código de prueba para que sea más fácil leerlas cuando las publique aquí. – GrandMasterFlush

5

que se olvidó de restablecer la posición de la secuencia de memoria:

private void Test() 
{    
    System.IO.MemoryStream data = new System.IO.MemoryStream(); 
    System.IO.Stream str = TestStream(); 

    str.CopyTo(data); 
    // Reset memory stream 
    data.Seek(0, SeekOrigin.Begin); 
    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length);      
} 

Actualización:

Hay una cosa más a tener en cuenta: Por lo general paga no ignorar los valores de retorno de métodos. Una implementación más robusta debería verificar cuántos bytes se han leído después de que la llamada regrese:

private void Test() 
{    
    using(MemoryStream data = new MemoryStream()) 
    { 
     using(Stream str = TestStream()) 
     { 
      str.CopyTo(data); 
     } 
     // Reset memory stream 
     data.Seek(0, SeekOrigin.Begin); 
     byte[] buf = new byte[data.Length]; 
     int bytesRead = data.Read(buf, 0, buf.Length); 

     Debug.Assert(bytesRead == data.Length, 
        String.Format("Expected to read {0} bytes, but read {1}.", 
         data.Length, bytesRead)); 
    }      
} 
Cuestiones relacionadas