Existe algum perigo em escrever bytes brutos em um arquivo? [fechadas]

12

Estou trabalhando com um problema em Programming Pearls - especificamente, a implementação de um programa que classifica um arquivo que contém, no máximo, 10.000.000 de números inteiros (coluna 1, problema 3). Como o livro não especifica como os dados devem ser armazenados no arquivo, estou pensando em armazenar os números inteiros como bytes brutos (existem outras restrições que tornam os bytes brutos uma boa opção). Eu nunca trabalhei nesse nível mais baixo antes, então quero saber se há algo perigoso que eu deva prestar atenção. Preciso me preocupar em usar acidentalmente algum tipo de sequência de fim de arquivo ao gravar bytes brutos em um arquivo, por exemplo?

Editar:

Agora percebo o quão ampla minha pergunta foi. Eu realmente quis dizer problemas do tipo mais catastrófico, como substituir acidentalmente outros arquivos no disco. Desculpe, eu não estava mais claro originalmente.

Drake Sobania
fonte
6
Observe que a programação de pérolas é um livro muito antigo; você pode facilmente ler os 10 ^ 7 inteiros inteiros na memória de uma máquina moderna, fazer a classificação e escrevê-la novamente. Para obter o ponto original desse capítulo, limite a quantidade que você lê a qualquer momento a uma fração do número total. Ou, aumente o tamanho do arquivo para cerca de 10 ^ 10 números inteiros.
Caleb
3
Na verdade, quando ouço a palavra "perigoso", penso em coisas que fazem meu PC explodir, excluir minhas contas bancárias ou algo assim. E acho que provavelmente é seguro supor que - desde que seu programa não seja usado para controlar um Airbus ou uma usina - nada realmente "perigoso" acontecerá quando você tentar o que tem em mente.
Doc Brown
2
@delnan Anos atrás, quando o mito do personagem EOF estava em voga, lembro-me de sistemas de proteção contra cópias baseados em 'copiar até o personagem EOF' que muitos programas de cópia da época faziam. Alguns programas colocariam dados adicionais que eles procurariam após o marcador EOF de um arquivo de texto associado, mas antes do final do arquivo alocado. O programa de cópia não copia os dados extras validando uma instalação limpa ... ahh ... nostalgia.
Perigo? Como em "meu computador explodirá se eu fizer isso"? Não.
Jwenting 28/08/14

Respostas:

11

O único perigo em que você se depara é pouca ou grande resistência (se o byte mais ou menos significativo é escrito primeiro). No entanto, se você permanecer no mesmo ambiente, não haverá problema. além da garantia geral de escrever / analisar ida e volta.

O sistema de arquivos foi projetado para lidar com qualquer sequência de bytes.

catraca arrepiante
fonte
2
+1 para a última linha. Não sei se o problema grande / pequeno é o único problema - o OP pode, por exemplo, ficar confuso sobre onde estão os limites entre números inteiros. Mas boa resposta de qualquer maneira.
Caleb
27

Não, na verdade é assim que muitos formatos de arquivo funcionam. Exemplos comuns de arquivos binários como este incluem imagens e arquivos de música / áudio.

Para manter a integridade do arquivo e os dados lidos, certifique-se de seguir estas diretrizes:

  • Sempre abra o arquivo (leitura ou gravação) usando o mesmo modo: texto ou binário. A principal diferença é que o modo de texto se preocupa com as novas linhas e pode "chomp" os caracteres das novas linhas ao ler um arquivo (dependendo da biblioteca específica que está sendo usada). O modo de texto também pode executar traduções Unicode que provavelmente serão bloqueadas em dados não Unicode.
  • Ao ler dados que não sejam de sequência, certifique-se de ler usando o mesmo tipo de dados que você escreve. Por exemplo, se os quatro primeiros bytes do arquivo forem um número inteiro descritivo, leia e grave usando um método que utiliza / fornece um número inteiro para garantir que ele seja tratado de forma consistente. O mesmo tipo de dados pode ter um tamanho diferente em máquinas diferentes, e a mistura de tipos de dados na mesma máquina também pode alterar o significado dos dados (por exemplo, interpretar um bit no meio de um número inteiro mais longo como um bit de sinal).
  • Endianness: se a biblioteca que você está usando não lida com isso de forma consistente, você pode precisar lidar com isso sozinho. Por exemplo, Java sempre usa ordem de bytes de rede (big endian) para tipos de vários bytes. C e C ++ usam o que o implementador da biblioteca decidiu, normalmente o mesmo que o processador (little endian na Intel, big endian na maioria dos outros). Se este é um exercício rápido em um sistema, não é tão importante, mas ainda é um bom hábito prestar atenção a isso e codificá-lo, se necessário.

Os detalhes específicos variarão com base na estrutura, plataforma e idioma, mas isso deve cobrir as "dicas" básicas do arquivo de E / S.


fonte
3
Um ponto adicional para dados que não são de cadeia: certifique-se de usar um número consistente de bytes para cada tipo. Em C e C ++, um intpode estar em qualquer lugar entre 2 e 8 ou mais bytes (octetos, na verdade).
Bart van Ingen Schenau 28/08/14
Isso está implicitamente incluído no meu segundo ponto, por exemplo, número inteiro de 32 v. 64 bits. Eles seriam diferentes tipos de dados.
Você pode torná-lo explícito. Não é óbvio que intem duas máquinas diferentes possam ser considerados tipos de dados diferentes.
Bart van Ingen Schenau
9

Além de todas as dicas já mencionadas, se você estiver criando um novo formato de arquivo binário em vez de ler e gravar dados em um formato existente, é absolutamente vital que você inclua um cabeçalho de arquivo : um bloco de dados no início do arquivo que identifica inequivocamente o formato do arquivo e registra todos os metadados necessários.

Bons cabeçalhos de arquivo incluem pelo menos três coisas:

  • Um " número mágico ", de pelo menos quatro bytes. O número mágico DEVE rfc2119 ser os primeiros N bytes no arquivo, nunca deve ter sido usado para qualquer outro formato de arquivo que você possa desenterrar e DEVE conter pelo menos um byte que não seja um caractere ASCII imprimível. Veja a especificação PNG para saber como criar um número mágico realmente completo . Veja o código-fonte do file(1)comando para obter um banco de dados de números mágicos existentes, tão abrangente quanto você provavelmente encontrará.

    O objetivo de um número mágico é rotular inequivocamente o arquivo, dentro da banda, com seu formato. Se você não incluir um número mágico ou não for a primeira coisa no arquivo, você corre o risco de os programas identificarem incorretamente seu arquivo como algum outro tipo de arquivo, o que leva à perda de dados, à fuga de vírus e à detecção de outros. catástrofes.

  • Uma indicação da versão do formato do arquivo. Mesmo que você ache que nunca precisará revisar drasticamente o formato do arquivo, crie os próximos dois bytes após o número mágico 00 00e documente que esse é um número de versão de 16 bits com alguma definição definitiva (o que você quiser, mas escolha um e cole-o ao longo do arquivo ) e será incrementado se o significado dos dados subsequentes mudar radicalmente. Seu futuro eu agradecerá.

    (A especificação PNG segue uma rota diferente aqui, especificando que os formatos de bloco são congelados e que todas as alterações futuras no formato terão a forma de novos tipos de bloco. Isso também é válido, mas eu recomendo a abordagem simples de número mágico + número de versão para iniciantes no processamento de dados binários. As pessoas que criaram o PNG usavam décadas de experiência coletiva com formatos de imagem.)

  • Algum tipo de mecanismo para incorporar metadados arbitrários no arquivo. Isso pode ser tão simples quanto fazer com que os próximos dois bytes sejam um deslocamento de 16 bits do final do cabeçalho até o início dos dados reais, com tudo entre os dois a ser interpretado como pares de valores-chave UTF-8 na RFC 822 (ou seja, " Tag: value\n" - se você seguir esse caminho, recomendo não permitir dobrar linhas longas). Mais uma vez, PNG é consideravelmente mais inteligente.

zwol
fonte
Não há necessidade de criar seu próprio formato de arquivo ... apenas armazene os dados como uma imagem. Pode ser necessário alterar a dimensionalidade (por exemplo, 10k x 1k) para que seja suportada. Ou você pode usar o FITS . Se seus dados são mais complexos do que apenas uma única matriz, você pode usar HDF , CDF ou NetCDF .
Joe
Eu sugiro mantê-lo simples. 256 versões diferentes serão suficientes e, se não, versões adicionais poderão ser criadas como subversões da versão 255. Da mesma forma, para os metadados, basta adicioná-los à versão quando eles forem realmente necessários. @Joe Image ??? Você está evitando a possível confusão de formatos, confundindo todos com antecedência!
maaartinus
@maaartinus Fazer o campo da versão em dois bytes força o designer de formato a se comprometer com um endianness logo no início. O espaço para metadados sempre deve estar na versão 0 de um formato binário, caso contrário, você acaba com kludges horríveis como o ID3. Eu tenho muita simpatia pela lógica das especificações PNG em relação à extensibilidade por meio de novos tipos de chunk, em vez de solavancos de versão de formato. No entanto, os arquivos estruturados em blocos trazem uma complexidade própria, então hesito em recomendá-los para casos simples. Eu estava tentado a recomendar HDF como um formato genérico que lidou com muitos já estas questões.
Zwol 29/08/14
2

Arquiteturas diferentes têm representações diferentes para números inteiros. O principal risco aqui é salvar a representação de bytes de um número inteiro na máquina A e, em seguida, tentar lê-lo e interpretar o conteúdo como números inteiros na máquina B. Se as máquinas A e B tiverem tamanhos diferentes para números inteiros e / ou endianidade diferente , você ' Muito provavelmente, causará um comportamento indefinido (por exemplo, em C) ou uma exceção.

Como este é apenas um exemplo de programação e não um programa "real", não é realmente um problema. Se esse fosse um programa real, rolar o seu próprio formato binário específico do aplicativo geralmente não é uma boa ideia; existem soluções melhores, como SQLite ou formatos de serialização baseados em string, como JSON, YAML, XML, etc. Para valores únicos, transformá-lo em uma string seria suficiente; para listas simples, você pode salvar uma string por linha e simplesmente dividir a entrada em novas linhas quando a ler novamente.

Doval
fonte
Concordo em geral, mas JSON ou XML aumentaria significativamente o tamanho de um arquivo contendo 10 ^ 7 números. Além disso, eles geralmente são lidos e analisados ​​de uma só vez, mas o capítulo em questão trata da classificação de arquivos que contêm mais dados do que os que podem caber na memória disponível.
Caleb
Depende do que você está fazendo. Às vezes, o impacto no desempenho do SQL versus um roll-your-own é grande. A última vez que fiz isso, eu tinha registros pequenos e havia uma grande chance de eu querer vizinhos. Ler um bloco maior do disco geralmente custaria quase nada; portanto, se eu quisesse um registro, leria 1000 em um cache. Meus registros estavam quase certamente próximos um do outro, com SQL, a cabeça do disco estaria saltando por todo o lugar.
Loren Pechtel 28/08/14