Pregunta

Tenemos alguna información que necesitamos escribir (unos 18 kb) a un archivo .txt almacenado en una de nuestras unidades de red. El archivo se reescribe aproximadamente una vez cada 15 minutos, pero se lee prácticamente al menos cada segundo. Actualmente estamos utilizando StreamWriter para escribir el archivo.

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

El problema es que a veces tarda hasta seis segundos en escribir el contenido del archivo, lo que definitivamente es demasiado largo incluso después de considerar la velocidad de la red.

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

¿Fue útil?

Solución

La opción más rápida:

Recopile todo su texto en una cadena grande primero y luego use System.IO.File.WriteAllText(text).

Otros consejos

Esta función fue escrita para leer desde una base de datos y salida a un archivo de texto. No dude en 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

Considere esto a su vez:

  1. Crea el archivo localmente
  2. Copiéelo a una carpeta remota con una extensión temporal
  3. Cambie el nombre del archivo remoto al nombre de su archivo original

El paso 2 y 3 es el siguiente (usando 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 archivo.copy toma el tiempo. Pero dado que no bloquea el archivo real que las personas están usando, no se bloquea. El segundo archivo.copy simplemente renombra el archivo y reemplaza el archivo real con el que recién cargado. File.delete elimina el archivo temporal cargado.

Espero que ayude.

Hay un par de cosas que entran en vigencia aquí. Pero he descubierto que utilizar el Io.file.appendText La función acelera los procesos de escritura inmensamente.

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

Ver Acelerar la redacción de archivos.

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

Escriba todo el texto a la vez usando:
System.io.file.writeAllText (ruta como cadena, contenido como cadena).

Sin embargo, aún tomará 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 a través del archivo anterior y luego elimine el archivo temporal.

Si quieres ser De Verdad Seguro que nadie lee 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 manejen con gracia los archivos no encontrados errores que inevitablemente sucederán de vez en cuando.

Considere escribir primero en una unidad local, luego trasladar ese archivo a su unidad de red.

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top