Existe um leitor de binário em C ++ para ler dados escritos em um escritor de binário em C#?
-
20-09-2019 - |
Pergunta
Eu escrevi vários INTs, char [] e tal para um arquivo de dados com o BinaryWriter em C#. Lendo o arquivo de volta (em C#) com o BinaryReader, posso recriar todas as peças do arquivo perfeitamente.
No entanto, tentar lê -los de volta com C ++ produz alguns resultados assustadores. Eu estava usando o FStream para tentar ler os dados e os dados não estavam lendo corretamente. Em C ++, eu configurei um Fream com ios::in|ios::binary|ios::ate
e usado Seekg para segmentar minha localização. Eu li os próximos quatro bytes, que foram escritos como o número inteiro "16" (e lê corretamente em C#). Isso parece 1244780 em C ++ (não no endereço de memória, eu verifiquei). Por que isso seria? Existe um equivalente ao BinaryReader em C ++? Percebi que isso mencionou no MSDN, mas isso é Visual C ++ e Intellisense nem se parecem com C ++, para mim.
Exemplo Código para escrever o arquivo (C#):
public static void OpenFile(string filename)
{
fs = new FileStream(filename, FileMode.Create);
w = new BinaryWriter(fs);
}
public static void WriteHeader()
{
w.Write('A');
w.Write('B');
}
public static byte[] RawSerialize(object structure)
{
Int32 size = Marshal.SizeOf(structure);
IntPtr buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(structure, buffer, true);
byte[] data = new byte[size];
Marshal.Copy(buffer, data, 0, size);
Marshal.FreeHGlobal(buffer);
return data;
}
public static void WriteToFile(Structures.SomeData data)
{
byte[] buffer = Serializer.RawSerialize(data);
w.Write(buffer);
}
Não tenho certeza de como eu poderia mostrar o arquivo de dados.
Exemplo de leitura dos dados de volta (C#):
BinaryReader reader = new BinaryReader(new FileStream("C://chris.dat", FileMode.Open));
char[] a = new char[2];
a = reader.ReadChars(2);
Int32 numberoffiles;
numberoffiles = reader.ReadInt32();
Console.Write("Reading: ");
Console.WriteLine(a);
Console.Write("NumberOfFiles: ");
Console.WriteLine(numberoffiles);
Isso eu quero me apresentar no C ++. Tentativa inicial (falha no primeiro número inteiro):
fstream fin("C://datafile.dat", ios::in|ios::binary|ios::ate);
char *memblock = 0;
int size;
size = 0;
if (fin.is_open())
{
size = static_cast<int>(fin.tellg());
memblock = new char[static_cast<int>(size+1)];
memset(memblock, 0, static_cast<int>(size + 1));
fin.seekg(0, ios::beg);
fin.read(memblock, size);
fin.close();
if(!strncmp("AB", memblock, 2)){
printf("test. This works.");
}
fin.seekg(2); //read the stream starting from after the second byte.
int i;
fin >> i;
EDIT: Parece que, independentemente do local que eu uso "Seekg", recebo exatamente o mesmo valor.
Solução
Você percebe que um char é de 16 bits em C#, em vez do 8 que geralmente está em C. Isso ocorre porque um char em C# foi projetado para lidar com o texto Unicode em vez de dados brutos. Portanto, escrever chars usando o BinaryWriter resultará na escrita Unicode em vez de bytes brutos.
Isso pode ter levado você a calcular o deslocamento do número inteiro incorretamente. Eu recomendo que você dê uma olhada no arquivo em um editor hexadecimente e, se você não puder resolver o problema, poste o arquivo e o código aqui.
Edit1
Em relação ao seu código C ++, não use o operador >> para ler em um fluxo binário. Use read () com o endereço do int que você deseja ler.
int i;
fin.read((char*)&i, sizeof(int));
Edit2
A leitura de um fluxo fechado também resultará em comportamento indefinido. Você não pode ligar para Fin.Close () e ainda espera poder ler.
Outras dicas
Isso pode ou não estar relacionado ao problema, mas ...
Quando você cria o BinaryWriter, ele padroniza para escrever char
s em UTF-8. Isso significa que alguns deles podem ser mais longos que um byte, jogando fora suas buscas.
Você pode evitar isso usando o 2 Argument construtor para especificar a codificação. Uma instância de System.Text.ASCIIEncoding
seria o mesmo que o uso de C/C ++ por padrão.
Há muitas coisas dando errado no seu snippet C ++. Você não deve misturar leitura binária com leitura formatada:
// The file is closed after this line. It is WRONG to read from a closed file.
fin.close();
if(!strncmp("AB", memblock, 2)){
printf("test. This works.");
}
fin.seekg(2); // You are moving the "get pointer" of a closed file
int i;
// Even if the file is opened, you should not mix formatted reading
// with binary reading. ">>" is just an operator for reading formatted data.
// In other words, it is for reading "text" and converting it to a
// variable of a specific data type.
fin >> i;
Se for ajuda, passei por como o BinaryWriter escreve dados aqui.
Já faz um tempo, mas vou citar e espero que seja preciso:
- O INT16 é escrito como 2 bytes e acolchoado.
- Int32 é escrito como pequeno endian e zero acolchoado
- Os carros alegóricos são mais complicados: leva o valor da flutuação e a desreferências, obtendo o conteúdo do endereço da memória que é um hexadecimal