Criar um arquivo de um tamanho específico não importando sua extensão

Bom dia galera, me deparei com uma tarefa que no início achei simples mas está me dando um pouco de dor de cabeça.
Preciso completar o espaço livre de um disco (Ex. Uma partição de um Pen Drive, uma Partição do HD) mas preciso realizar isso da forma mais rápida possível.

A solução que encontrei foi a seguinte:

Como preciso ocupar o espaço livre de um disco pensei em criar um arquivo do tamanho do espaço livre. Chamo isso de POG mas tudo bem… rsrsrsr
Sendo assim criei essa classe.

[code]package teste;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class CompletarEspacoLivre {

public CompletarEspacoLivre(File arquivoDestino, int espacoLivre) throws IOException {

//Recebo como parâmetro do construtor o caminho + o nome do arquivo que será gerado e
// o espaço livre do disco que será usado como base para a criação do arquivo.

	if (arquivoDestino.exists())
		arquivoDestino.delete();

	FileChannel destinationChannel = null;
	ByteBuffer bytes = ByteBuffer.allocate(espacoLivre);

//Crio o ByteBuffer alocando o tamanho do espaço livre do disco

	try {
		destinationChannel = new FileOutputStream(arquivoDestino).getChannel();
		destinationChannel.write(bytes);

//E finalmente escrevo o arquivo com a quantidade de bytes necessária

	} finally {
		if (destinationChannel != null && destinationChannel.isOpen())
			destinationChannel.close();
	}
}

}
[/code]

Funciona perfeitamente (Aparentemente), no entanto gostaria de saber se esta forma seria a melhor solução para preencher o espaço livre de um disco mantendo uma boa performance.

Desde já agradeço a atenção!
Abraços!

a) Você só testou seu programa com pendrives pequenos - e os arquivos com mais de 2GB? (Embora, obviamente, se o pendrive estiver formatado como FAT você terá dificuldade de criar um arquivo com mais de 2 GB)?

b) Se o pendrive ou HD estiver formatado como NTFS e ele estiver configurado para comprimir os arquivos, o que irá ocorrer é que mesmo que você saiba o espaço vazio disponível, o código que você escreveu (que preenche o espaço com zeros) irá criar um arquivo que será muito compressível (afinal de contas são apenas zeros binários).

Recomendo usar um programa em C ++ mesmo, que deve ser fácil de achar na Internet. Esses programas costumam gravar dados aleatórios em vez de zeros binários, e os dados aleatórios não são compressíveis, portanto o espaço disponível será integralmente preenchido.

A aplicação final será para Android, sendo assim preencherei o SDCard que no máximo terá 32GB e estará sempre no formato FAT.
Como vai ser para Android tem que ser em JAVA mesmo.

Percebi uma falha aqui no código, o tamanho máximo de alocação de buffer da dalvikvm é de 67108864 bytes sendo assim se o espaço livre for maior que isso vai gerar uma exeption. Sendo assim teria de fazer um laço definindo um buffer constante e repetindo até o espaço ser completamente preenchido.

Dependendo de como foi formatado o SDCard (FAT32? exFAT?) nao se pode criar um arquivo com mais de 2GB. É melhor criar vários arquivos, então.

Olhe em http://en.wikipedia.org/wiki/File_Allocation_Table os limites.

Os SDCards utilizados pelo Android são formatados com FAT32.

Não sei se é a única forma de “encher” um disco mas eu pensei nessa possibilidade de criar um arquivo assim como quando baixamos um torrent de por exemplo 5GB onde antes mesmo do arquivo ser baixado o espaço necessário para ele já é previamente alocado no disco.

Pois bem, seu cliente de Torrent deve estar usando NTFS (Windows XP, 7, 8 etc.) ou algum filesystem do Linux (que nao tem essa limitacao).

O FAT32 tem a limitação de 4GB e acabou. Portanto, se você tiver um SD de 32 GB, precisará criar vários arquivos.

Só por curiosidade, poderia checar se a seguinte sequencia de eventos:

java.io.RandomAccessFile raf = new RandomAccessFile (.....);
raf.seek (2000000000L);
raf.write (0);
raf.close();

cria um arquivo de 2000000000 bytes? Só por curiosidade.

Sim! O arquivo é criado com o tamanho informado.
Mas percebi que levou um tempo considerável…
Acha que é possível otimizar a velocidade?

Use um SDCard mais rápido :slight_smile:

Nesse caso, em que chamamos seek, o Java na verdade está chamando uma API do Linux que faz exatamente o que você quer (criar um arquivo com o tamanho determinado).
Por motivos de segurança, em vez de simplesmente reservar o espaço, o Linux, quando escrevemos nessa posição 2 bilhões, preenche todas as posições anteriores com zeros.
E esse preenchimento é que demora um monte de tempo. Como não existem arquivos “esparsos” em FAT, o Linux é obrigado a fazer isso (fazer a gravação física).

Estou falando “Linux” porque, como você deve saber, o Android nada mais é que uma distribuição do Linux :slight_smile:

Note que se o SDCard fosse formatado com extfs ou outro filesystem típico do Linux (como o JFS, XFS, Reiser etc.), seria criado um arquivo “esparso” (ou seja, posições não escritas não são escritas fisicamente no disco) e o “write” voltaria instantaneamente. Mas como o SDCard é FAT não existem arquivos “esparsos”.

Entendi entanglement, era exatamente o que eu estava procurando.
Cara muito obrigado! Ajudou muito mesmo hoje vou fazer testes usando SDCards classe 6 e 10 para ver analisar a diferença entre os tempos.
Vou tentar formatar o SD com outros sistemas de arquivos como os que você citou abaixo.

Abraços!

Não faça isso - aí você vai ter de gravar um arquivo com dados aleatórios; se você simplesmente criar um arquivo esparso, não vai sobreescrever eventual informação sigilosa que você quer proteger, e se bobear até vai fazer com que o Linux reporte que o espaço não está sendo usado (ou seja, deixe você gravar mais bytes que a capacidade nominal do SD) - queria saber se é por isso que você quer “lotar” o disco. É para sobreescrever o cartão para que ninguém possa “desapagar” os dados já contidos?

Então… Em primeira instância o objetivo encher o cartão sobrescrevendo-o só não entendi a parte do ninguém poder “desapagar” os dados já contidos rsrsrsr

É assim. Digamos que o Linux executasse a sequencia do seu programa Java simplesmente criando um arquivo de 2GB, mas não apagando o que já existia lá.
Você poderia recuperar com facilidade o que já estava escrito dentro do cartão (embora tivesse de juntar os pedaços :slight_smile: )

Que interessante… Se o arquivo fosse por exemplo um arquivo multimidia, o player conseguiria executá-lo mesmo que pequenos trechos?