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.

Foi útil?

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 chars 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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top