2011-01-24 8 views
6

Tenemos información que debemos escribir (aproximadamente 18   KB) en un archivo .txt almacenado en una de nuestras unidades de red. El archivo se vuelve a escribir una vez cada 15 minutos, pero se lee prácticamente al menos cada segundo. Actualmente estamos usando StreamWriter para escribir el archivo.Manera eficiente de escribir en un archivo de texto en VB.NET

El servidor de archivos está en una ubicación remota y el ping de ida y vuelta varía desde menos de 1   ms hasta 15   ms.

El problema es que, a veces, se necesitan hasta seis segundos para escribir los contenidos en el archivo, lo cual es demasiado largo incluso después de considerar la velocidad de la red.

Por lo tanto, me pregunto si existe alguna forma eficiente de escribir el archivo usando VB.NET para mejorar el rendimiento. Java tiene una herramienta muy buena llamada BufferedOutputStream, que desafortunadamente no está disponible en VB.NET (o simplemente no la he encontrado).

+1

StreamWriter ya está en el búfer. –

+0

Solo un pensamiento. Si lo está leyendo con tanta frecuencia, es posible que experimente algunos problemas de contención, múltiples lecturas que bloquean el archivo contra la escritura durante un breve período, lo que ocasiona un retraso ocasional en la escritura del archivo. – DarinH

+0

¿Cuál es la velocidad de la red? De lo bajo, la contención, como la describe drventure, podría ser el culpit. ¿Y la conexión es utilizada por otros programas/usuarios ?. – MarcelDevG

Respuesta

12

La opción más rápida:

Recoger todos su texto en una cadena grande, luego utilice System.IO.File.WriteAllText(text).

1

Hay un par de cosas que entran en vigor aquí. Pero descubrí que utilizar la función IO.File.AppendText acelera enormemente los procesos de escritura.

Además, el uso de la clase System.Text.Stringbuilder en lugar de una cadena tradicional (suponiendo que está concating el texto para escribir en un archivo) mejora la velocidad aún más.

Ver Speeding up File Writing.

+0

Mmm ... parece que este apéndice suena muy prometedor, muchas gracias por el artículo, lo intentaré y le haré saber, ¡gracias! – AZhu

1

Esta función se escribió para leer desde una base de datos y salir a un archivo de texto. Por favor, siéntase libre de usarlo como punto de partida.

Sub MakeFile(ByVal Obj As Object) 
    Dim CountRow As Integer = 0 
    Dim TableName As String = CType(Obj, String())(0) 
    Dim CommandText As String = CType(Obj, String())(1) 


    Dim csvFileName As String = InitilizationSettings.DirectoryPath & TableName & ".txt" 
    If File.Exists(csvFileName) Then 
     File.Delete(csvFileName) 
    End If 
    Dim buffer() As Byte = {255} 
    Dim FileObject As New FileStream(csvFileName, FileMode.OpenOrCreate) 
    Dim MStream As New MemoryStream() 
    Dim StreamWriterObj As New StreamWriter(MStream) 
    Dim sb As New System.Text.StringBuilder 
    Dim x As Integer = 0 

    Dim reader As SqlDataReader 
    Dim cmd As New SqlCommand() 
    Dim conn As New SqlConnection(IOUtilities.GetConnectionString()) 


    conn.Open() 


    With cmd 
     .CommandText = CommandText 
     .CommandTimeout = 1200 
     .CommandType = CommandType.Text 
     .Connection = conn 
    End With 

    reader = cmd.ExecuteReader() 

    Do While reader.Read() 
     'System.Console.Write("Loading rows to memory.../" & vbCr) 
     sb.Append(Chr(34)) 
     sb.Append(reader.Item(0)) 
     'System.Console.Write("Loading rows to memory...|" & vbCr) 
     sb.Append(Chr(34)) 
     For i = 1 To reader.FieldCount - 1 
      sb.Append(",") 
      sb.Append(Chr(34)) 
      sb.Append(reader.Item(i)) 
      sb.Append(Chr(34)) 
     Next 
     'System.Console.Write("Loading rows to memory...\" & vbCr) 



     sb.AppendLine() 

     'Write every 10000 rows of data to the file from the buffer 
     If x = 50000 Then 
      StreamWriterObj.Write(sb.ToString().ToCharArray()) 
      MStream.Seek(0, SeekOrigin.Begin) 
      MStream.WriteTo(FileObject) 
      sb = New StringBuilder() 
      CountRow = CountRow + x 
      x = 0 
     End If 
     'System.Console.Write("Loading rows to memory...-" & vbCr) 
     x = x + 1 


     'LogEvents("Dumped " & strFileName & " to " & GetFilePath() & " at " & Now.ToString & vbCrLf & vbCrLf) 
    Loop 

    conn.Close() 
    reader.Close() 
    'Write any remaining data from the buffer to the file 
    StreamWriterObj.Write(sb.ToString().ToCharArray()) 
    MStream.WriteTo(FileObject) 
    FileObject.Close() 

    System.Console.WriteLine(String.Format(vbCrLf & "Finished writing data to {1}", CountRow, csvFileName)) 

End Sub 
-1

Considere escribir primero en un disco local y luego mover ese archivo a la unidad de red.

1

Considere estos a su vez:

  1. Crear el archivo localmente
  2. copiarlo a la carpeta remota con una extensión temporal
  3. Cambie el nombre del archivo remoto a su nombre de archivo original

Paso 2 y 3 es el siguiente (utilizando System.IO):

string OriginalExtension = ".ok", TemporaryExtension = ".dat"; 
string tmpFileRemote = RemoteFile.Replace(TemporaryExtension, OriginalExtension); 
File.Copy(fileName, RemoteFile, true); 
File.Copy(RemoteFile, tmpFileRemote, true); 
File.Delete(RemoteFile); 

El primer File.Copy toma el tiempo. Pero como no bloquea el archivo real que las personas están usando, no se bloquea. El segundo File.Copy simplemente cambia el nombre del archivo y reemplaza el archivo real con el que acaba de subir. File.Delete elimina el archivo temporal cargado.

Espero que ayude.

-1
Sub writefile() 
    Dim file As System.IO.StreamWriter 
    file = My.Computer.FileSystem.OpenTextFileWriter("N:\GeneratedNumber.txt", False) 
    file.WriteLine("Player1 Skill is " & Skill(0)) 
    file.WriteLine("Player1 Strength is " & Skill(1)) 
    file.WriteLine("Player2 Skill is " & Skill(2)) 
    file.WriteLine("Player2 Strength is " & Skill(3)) 
    file.Close() 
End Sub 
+0

Sería bueno si pudieras explicar cómo tu respuesta es más eficiente (como lo exige la pregunta) que las respuestas existentes. Además, utilice "Muestra de código" en el menú para resaltar el código. – gsk

0

Un hilo viejo, pero creo que todavía hay algo que añadir:

Escribir todo el texto a la vez usando:
System.IO.File.WriteAllText (ruta como secuencia, contenido como secuencia).

Sin embargo, todavía llevará tiempo escribir el archivo si se está escribiendo a través de una conexión lenta a una ubicación remota. Para evitar que los usuarios lean un archivo parcialmente escrito, debe escribir los datos en un archivo temporal en el servidor remoto. Una vez que se hayan escrito todos los datos, copie el archivo temporal sobre el archivo anterior y luego elimine el archivo temporal.

Si quiere ser realmente asegúrese de que nadie lea un archivo parcialmente escrito, puede eliminar el archivo anterior y luego mover/cambiar el nombre del archivo temporal para reemplazar el archivo que acaba de eliminar. En este caso, debe asegurarse de que los programas del cliente gestionen correctamente los errores de archivo no encontrado que inevitablemente ocurrirán de vez en cuando.

Cuestiones relacionadas