0x00 em um arquivo binário VB.NET
-
20-09-2019 - |
Pergunta
ATUALIZADO ABAIXO
Estou lendo um arquivo binário usando BinaryReader em VB.NET.A estrutura de cada linha do arquivo é:
"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)
O problema é que o campo "Texto" possui alguns caracteres estranhos usados para preenchimento.A maioria parece ser 0x00 caracteres nulos.
Existe alguma maneira de se livrar desses caracteres 0x00 por alguma codificação?
Caso contrário, como posso substituir a matriz chText para me livrar dos caracteres 0x00?Estou tentando serializar a tabela de dados resultante para XML e está falhando nesses caracteres não compatíveis.Consigo percorrer o array, porém não consigo descobrir como fazer a substituição?
ATUALIZAR:
É aqui que estou com muita ajuda dos rapazes/garotas abaixo.A primeira solução funciona, porém não tão flexível quanto eu esperava, a segunda falha para um caso de uso, porém é muito mais genérica.
Anúncio 1) Posso resolver o problema passando a string para esta sub-rotina
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
Anúncio 2) Esta rotina elimina vários caracteres incorretos, mas falha em 0x00.Isto foi adaptado do MSDN, http://msdn.microsoft.com/en-us/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
Solução
Primeiro de tudo você deve descobrir qual é o formato do texto, para que você esteja apenas removendo algo às cegas, sem saber o que acertou.
Dependendo do formato, você usa métodos diferentes para remover os caracteres.
Para remover apenas os caracteres zero:
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 remover tudo, desde o primeiro caractere zero até o final do array:
Dim len As Integer
While len < byText.Length AndAlso byText(len) <> 0
len += 1
End While
strText = Encoding.ASCII.GetChars(byText, 0, len)
Editar:
Se você quiser apenas manter qualquer lixo que seja 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)
Outras dicas
Se os caracteres nulos forem usados como preenchimento direito (ou seja, encerrando) o texto, o que seria o caso normal, isso é 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
Se não, você ainda pode fazer um normal Replace
na corda.Seria um pouco mais “limpo” se você fizesse a poda na matriz de bytes, antes convertendo-o em uma string.O princípio permanece o mesmo, no entanto.
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)
Você pode usar uma estrutura para carregar os dados:
[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;
}
Você deve ajustar o argumento UnknownType para se adequar à sua codificação de string.