0x00 en un archivo binario VB.NET
-
20-09-2019 - |
Pregunta
ACTUALIZADO A CONTINUACIÓN
Estoy leyendo un archivo binario utilizando BinaryReader en VB.NET. La estructura de cada fila del archivo es:
"Category" = 1 byte
"Code" = 1 byte
"Text" = 60 Bytes
Dim Category As Byte
Dim Code As Byte
Dim byText() As Byte
Dim chText() As Char
Dim br As New BinaryReader(fs)
Category = br.ReadByte()
Code = br.ReadByte()
byText = br.ReadBytes(60)
chText = encASCII.GetChars(byText)
El problema es que el campo "Texto" tiene algunos caracteres extraños utilizados para el relleno. Sobre todo parece ser 0x00 caracteres nulos.
-
¿Hay alguna manera de deshacerse de estos 0x00 caracteres por algunos de codificación?
-
Si no, ¿cómo puedo hacer un reemplazo en la matriz chText para deshacerse de los caracteres 0x00? Estoy tratando de serializar la tabla de datos resultante para XML y está fallando en estos caracteres no compatibles. Soy capaz de recorrer la matriz, sin embargo no puedo encontrar la manera de hacer la sustitución?
ACTUALIZACIÓN:
Esto es donde estoy con mucha ayuda de los chicos / chicas de abajo. Las primeras soluciones funciona, sin embargo, no tan flexibles como lo esperaba, la segunda falla por un caso de uso, sin embargo es mucho más genérico.
Ad 1) puedo solucionar el problema pasando la cadena a esta subrutina
Public Function StripBad(ByVal InString As String) As String
Dim str As String = InString
Dim sb As New System.Text.StringBuilder
strNew = strNew.Replace(chBad, " ")
For Each ch As Char In str
If StrComp(ChrW(Val("&H25")), ch) >= 0 Then
ch = " "
End If
sb.Append(ch)
Next
Return sb.ToString()
End Function
Ad 2) Esta rutina hace lleva a cabo varios caracteres problemáticos, sin embargo falla por 0x00. Este fue adaptado de MSDN, http://msdn.microsoft.com/en- es / library / kdcak6ye.aspx .
Public Function StripBadwithConvert(ByVal InString As String) As String
Dim unicodeString As String
unicodeString = InString
' Create two different encodings.
Dim ascii As Encoding = Encoding.ASCII
Dim [unicode] As Encoding = Encoding.UTF8
' Convert the string into a byte[].
Dim unicodeBytes As Byte() = [unicode].GetBytes(unicodeString)
Dim asciiBytes As Byte() = Encoding.Convert([unicode], ascii, unicodeBytes)
Dim asciiChars(ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length) - 1) As Char
ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0)
Dim asciiString As New String(asciiChars)
Return asciiString
End Function
Solución
En primer lugar usted debe saber lo que el formato del texto es, por lo que se acaba de quitar algo a ciegas sin saber qué le golpeó.
Dependiendo del formato, se utilizan diferentes métodos para eliminar los caracteres.
Para eliminar sólo los caracteres cero:
Dim len As Integer = 0
For pos As Integer = 0 To byText.Length - 1
If byText(pos) <> 0 Then
byText(len) = byText(pos)
len += 1
End If
Next
strText = Encoding.ASCII.GetChars(byText, 0, len)
Para quitar todo, desde el primer carácter cero hasta el final de la matriz:
Dim len As Integer
While len < byText.Length AndAlso byText(len) <> 0
len += 1
End While
strText = Encoding.ASCII.GetChars(byText, 0, len)
Editar:
Si lo que desea es mantener ningún tipo de basura que pasa a ser caracteres ASCII:
Dim len As Integer = 0
For pos As Integer = 0 To byText.Length - 1
If byText(pos) >= 32 And byText(pos) <= 127 Then
byText(len) = byText(pos)
len += 1
End If
Next
strText = Encoding.ASCII.GetChars(byText, 0, len)
Otros consejos
Si se utilizan los caracteres nulos como relleno derecho (es decir, de terminación ) el texto, lo que sería el caso normal, esto es bastante fácil:
Dim strText As String = encASCII.GetString(byText)
Dim strlen As Integer = strText.IndexOf(Chr(0))
If strlen <> -1 Then
strText = strText.Substr(0, strlen - 1)
End If
Si no es así, todavía se puede hacer una Replace
normales en la cadena. Sería un poco más “limpia” si lo hizo la poda en el conjunto de bytes, antes convirtiéndola en una cadena. El principio es el mismo, sin embargo.
Dim strlen As Integer = Array.IndexOf(byText, 0)
If strlen = -1 Then
strlen = byText.Length + 1
End If
Dim strText = encASCII.GetString(byText, 0, strlen - 1)
Puede utilizar una estructura para cargar los datos:
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
internal struct TextFileRecord
{
[System.Runtime.InteropServices.FieldOffset(0)]
public byte Category;
[System.Runtime.InteropServices.FieldOffset( 1 )]
public byte Code;
[System.Runtime.InteropServices.FieldOffset( 2 )]
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr, SizeConst=60)]
public string Text;
}
Hay que ajustar el UnmanagedType-Argumento para encajar con su cadena de codificación.