Dica: Arquivos “dispersos”

Você já teve que escrever um arquivo binário com um monte de zeros? Suponha que seu programa tenha que escrever uma string pequena no início do arquivo, escrever um monte de zeros e escrever a string de novo… Será que não tem um jeito de fazer com que o sistema operacional grave esse monte de zeros para nós? Bem…. há!

A especificação POSIX prevê aquilo que é conhecido como sparse files. Basta saltar para a posição desejada, escrever alguma coisa e voilà, temos um monte de zeros entre a última escrita e a mais recente. E isso tem uma grande vantagem: Poupa espaço em disco! Vejamos um exemplo:

#include <stdio.h>
#include <string.h>

char *data = "fred";

void main(int argc, char *argv[])
{
  FILE *f;
  int fd;

  if (argc != 2)
  {
    fprintf(stderr, "Uso: sparse <filename>\n");
    return;
  }

  if ((f  = fopen(argv[1], "w")) == NULL)
  {
    fprintf(stderr, "Error creating sparse file '%s'.\n",
      argv[1]);
    return;
  }

  /* Escreve a string no início do arquivo. */
  fwrite(data, strlen(data), 1, f);

  /* Salta para a posição 10000 do arquivo. */
  fseek(f, 10000, SEEK_SET);

  /* Escreve a string, de novo. */
  fwrite(data, strlen(data), 1, f);

  fclose(f);
}

Aqui eu escrevo “fred” (obedecendo o  meu narcisismo delirante!) no início do arquivo, salto para a posição 10000 e escrevo “fred”, de novo. Eis o que acontece:

$ gcc -o sparse sparse.c
$ ./sparse file.bin
$ ls -l file.bin
total 1
-rw-rw-r--  1 fred fred 10004 Abr 19 08:22 file.bin

O valor depois das permissões do arquivo (em azul) é a quantidade de blocos (de 1024 bytes) ocupados em disco. Note que file.bin tem 10004 bytes (em verde) e deveria ocupar 10 blocos, mas só ocupa 1 único bloco. Se observarmos o conteúdo do arquivo:

$ hd file.bin
00000000  66 72 65 64 00 00 00 00  00 00 00 00 00 00 00 00  |fred............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00002710  66 72 65 64                                       |fred|
00002714

Veremos que todo o espaço onde não escrevemos estará preenchido com zeros… Mas, não estão gravados em disco.

Experimente alterar o offset na função fseek para 1073741824 (1 GB) e verá que o arquivo continuará ocupando apenas 1 único bloco em disco, embora seu tamanho passe a ser de 1 GB.

A boa notícia para vocês é que “arquivos dispersos”, que foi uma coisa criada para o UNIX, também está disponível em outras plataformas, como Windows, por exemplo!

Algumas considerações sobre arquivos “dispersos”:

  1. Se você copiar um arquivo “disperso” você poderá obter uma cópia “não-dispersa”. No Linux, por exemplo, se você usar o comando cp, estará copiando os i-nodes do arquivo… os “blocos” já contidos no disco, por assim dizer… Mas, se fizer um cat:
    $ cat file.bin > file2.bin

    Obterá um arquivo file2.bin com 10004 bytes e 10 blocos.

  2. Dito isso, é bom saber que a dispersão é um recurso do sistema de arquivos… NTFS e os file systems mais usados no UNIX têm esse recurso. Mas, FAT (muito usado em pendrives) não têm!
  3. Usar a técnica do arquivo disperso é uma boa maneira de garantir que o arquivo final caberá no disco, sem ter que escrever alguma coisa em todo o arquivo. Se o sistema operacional detectar que você está querendo criar um arquivo disperso que tem o potencial de ter o tamanho maior que o espaço livre em disco, a função fseek falhará, retornando -1 (o mesmo para lseek). Essa é a técnica usada por clientes de torrents, por exemplo… Um ou mais arquivos são criados e um fseek é feito para garantir que o arquivo tenha o tamanho total certo… mas, os blocos “reais” serão gravados depois.
Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s