2012-08-02 26 views
8

¿Hay alguna forma de escribir una función asíncrona que escribe datos en un archivo repetidamente?Escribir en un archivo de forma asíncrona

estoy recibiendo el siguiente error al escribir la función asíncrona

El proceso no tiene acceso al archivo 'c: \ Temp \ Data.txt' porque está siendo utilizado por otro proceso

public void GoButton_Click(object sender, System.EventArgs e) 
{ 
    IAsyncResult ar = DoSomethingAsync(strURL, strInput); 
    Session["result"] = ar; 
    Response.Redirect("wait1.aspx"); 
} 

private IAsyncResult DoSomethingAsync(string strURL, string strInput) 
{ 
    DoSomethingDelegate doSomethingDelegate = new DoSomethingDelegate(DoSomething); 
    IAsyncResult ar = doSomethingDelegate.BeginInvoke(strURL, strInput, new AsyncCallback(MyCallback), null); 
    return ar; 
} 

private delegate void DoSomethingDelegate(string strURL, string strInput); 

private void MyCallback(IAsyncResult ar) 
{ 
    AsyncResult aResult = (AsyncResult)ar; 
    DoSomethingDelegate doSomethingDelegate = (DoSomethingDelegate)aResult.AsyncDelegate; 
    doSomethingDelegate.EndInvoke(ar); 
} 

private void DoSomething(string strURL, string strInput) 
{ 
    int i = 0; 
    for (i = 0; i < 1000; i++) 
    { 
     m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); 
     m_streamWriter.WriteLine("{0} ", MethodCall(strURL, strInput)); 
     m_streamWriter.Flush(); 
     m_streamWriter.Close(); 
    } 
} 
+0

Sí, es posible. Asegúrese de no abrir el archivo en el hilo principal y no modificar usando otro. – Leri

+0

Dónde debería modificar el código –

+0

La excepción normalmente ocurrirá si abre una secuencia. Dentro del ejemplo del código dado, solo se escribe en una transmisión existente, pero falta el código donde se crea la transmisión (y se lanza la excepción). – Oliver

Respuesta

11

Bueno, tuve el mismo problema. Y lo resolvió ahora. Es una especie de sugerencia tardía, pero puede ser de ayuda para otros.

Incluya las siguientes instrucciones de uso en los ejemplos de la consola a continuación.

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Text; 
using System.Threading.Tasks; 
Use of the FileStream Class 

Los ejemplos siguientes utilizan la clase FileStream, que tiene una opción que hace que asíncrono I/O que se produzca a nivel del sistema operativo. En muchos casos, esto evitará bloquear un hilo de ThreadPool. Para habilitar esta opción, debe especificar el argumento useAsync = true u options = FileOptions.Asynchronous en la llamada del constructor.

StreamReader y StreamWriter no tienen esta opción si los abre directamente al especificar una ruta de archivo. StreamReader/Writer tiene esta opción si les proporciona un Stream que fue abierto por la clase FileStream. Tenga en cuenta que la asincronía proporciona una ventaja de capacidad de respuesta en las aplicaciones de interfaz de usuario, incluso si un hilo del grupo de subprocesos está bloqueado, ya que el subproceso de la interfaz de usuario no se bloquea durante la espera.

Escritura de texto

el siguiente ejemplo se escribe texto en un archivo. En cada declaración de espera, el método sale inmediatamente. Cuando se completa la E/S de archivo, el método se reanuda en la instrucción que sigue a la instrucción await. Tenga en cuenta que el modificador asíncrono está en la definición de métodos que usan la instrucción await.

static void Main(string[] args) 
{ 
    ProcessWrite().Wait(); 
    Console.Write("Done "); 
    Console.ReadKey(); 
} 

static Task ProcessWrite() 
{ 
    string filePath = @"c:\temp2\temp2.txt"; 
    string text = "Hello World\r\n"; 

    return WriteTextAsync(filePath, text); 
} 

static async Task WriteTextAsync(string filePath, string text) 
{ 
    byte[] encodedText = Encoding.Unicode.GetBytes(text); 

    using (FileStream sourceStream = new FileStream(filePath, 
     FileMode.Append, FileAccess.Write, FileShare.None, 
     bufferSize: 4096, useAsync: true)) 
    { 
     await sourceStream.WriteAsync(encodedText, 0, encodedText.Length); 
    }; 
} 

texto de la lectura

el siguiente ejemplo se lee el texto desde un archivo. El texto está almacenado en el búfer y, en este caso, colocado en un StringBuilder. A diferencia del ejemplo anterior, la evaluación de await produce un valor. El método ReadAsync vuelve una tarea, por lo que la evaluación de la Await produce un valor Int32 (numRead) que se devuelve después de la operación se completa ..

static void Main(string[] args) 
{ 
    ProcessRead().Wait(); 
    Console.Write("Done "); 
    Console.ReadKey(); 
} 

static async Task ProcessRead() 
{ 
    string filePath = @"c:\temp2\temp2.txt"; 

    if (File.Exists(filePath) == false) 
    { 
     Console.WriteLine("file not found: " + filePath); 
    } 
    else { 
     try { 
      string text = await ReadTextAsync(filePath); 
      Console.WriteLine(text); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 
} 

static async Task<string> ReadTextAsync(string filePath) 
{ 
    using (FileStream sourceStream = new FileStream(filePath, 
     FileMode.Open, FileAccess.Read, FileShare.Read, 
     bufferSize: 4096, useAsync: true)) 
    { 
     StringBuilder sb = new StringBuilder(); 

     byte[] buffer = new byte[0x1000]; 
     int numRead; 
     while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0) 
     { 
      string text = Encoding.Unicode.GetString(buffer, 0, numRead); 
      sb.Append(text); 
     } 

     return sb.ToString(); 
    } 
} 

se puede tomar un fuente original mirar desde Using Async for File Access

Esperanza eso ayuda ...

+0

Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. – StarsSky

+1

@StarsSky: Tienes razón, eso tiene sentido. Voy a editarlo. Gracias por la sugerencia – curiousBoy

+3

La respuesta tiene la solución ahora. – curiousBoy

4

Escribir de manera asíncrona al archivo no resolverá este problema. Tendrá que esperar a que el archivo esté disponible.

0

En última instancia, depende de por qué estás tratando de hacerlo.

Si no va a escribir demasiados datos en el archivo, puede abrirlo y cerrarlo constantemente.

Como alternativa, si sabe cuándo quiere que se abra el archivo y cuándo lo quiere cerrar, puede abrirlo cuando lo necesite y luego mantenerlo abierto hasta que sepa que ya no es necesario.

+0

Estoy haciendo algún tipo de prueba de carga para un servicio web. Algunas veces devuelve "El registro no existe" del Cliente. Quiero reproducir el problema ¿Dónde debo modificar el código para cerrar y abrir el archivo? ¿Podrías por favor compartir conmigo? –

+0

Bueno, no estoy seguro de cómo maneja los archivos (soy nuevo en C#, soy de un fondo VB) pero normalmente uso streamwriters/streamreaders (que también están en C#). Los Streamwriters abren el archivo con su método constructor y luego lo mantienen abierto para escribir hasta que se llame al método close. Entonces, cada vez que quería escribir algo en un archivo, podía hacer el constructor, el método de escritura y luego el método de cierre. Como dije antes, sin saber qué es lo que quiere lograr, no puedo recomendar cosas a tú. ¿Está tratando de actualizar constantemente el archivo por algún motivo? (por ejemplo, un juego) – Pharap

+0

Estoy haciendo repetidas visitas a un servicio web donde a veces arroja "El registro no existe" de nuestro cliente. Quiero reproducir el problema de mi lado de forma asincrónica. vb.net también está bien conmigo. Este es un tipo de prueba de carga para una llamada a un método web. Llamar al método de forma repetida y asincrónica es lo que quiero lograr. –

3

Ejemplo de un método auxiliar para manejar la escritura asíncrona en un archivo.

public async Task FileWriteAsync(string filePath, string messaage, bool append = true) 
    { 
     using (FileStream stream = new FileStream(filePath, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.None, 4096, true)) 
     using (StreamWriter sw = new StreamWriter(stream)) 
     { 
      await sw.WriteLineAsync(messaage); 
     } 
    } 
Cuestiones relacionadas