2008-09-19 5 views
14

Je crée une application de téléchargement et je souhaite préallouer de la place sur le disque dur pour les fichiers avant qu'ils ne soient réellement téléchargés car ils pourraient être plutôt volumineux, et personne n'aime voir "Ce lecteur est plein, s'il vous plaît supprimer quelques fichiers encore." Donc, dans cette optique, j'ai écrit ceci.Préallouer l'espace fichier en C#?

// Quick, and very dirty 
System.IO.File.WriteAllBytes(filename, new byte[f.Length]); 

Il fonctionne, atleast jusqu'à ce que vous téléchargez un fichier qui est plusieurs centaines de Mo de, ou peut-être même Go de et vous jetez Windows dans une frénésie raclée sinon éliminer totalement le fichier d'échange et de tuer vos systèmes de mémoire tout à fait. Oops. Donc, avec un peu plus d'illumination, je pars avec l'algorithme suivant.

using (FileStream outFile = System.IO.File.Create(filename)) 
{ 
    // 4194304 = 4MB; loops from 1 block in so that we leave the loop one 
    // block short 
    byte[] buff = new byte[4194304]; 
    for (int i = buff.Length; i < f.Length; i += buff.Length) 
    { 
     outFile.Write(buff, 0, buff.Length); 
    } 
    outFile.Write(buff, 0, f.Length % buff.Length); 
} 

Cela fonctionne bien, et ne souffre pas du problème de mémoire paralysant de la dernière solution. C'est quand même lent, surtout sur le matériel plus ancien car il écrit (peut-être la valeur de GB) des données sur le disque. La question est la suivante: Y a-t-il une meilleure façon d'accomplir la même chose? Existe-t-il un moyen de dire à Windows de créer un fichier de taille x et d'allouer simplement l'espace sur le système de fichiers plutôt que d'écrire réellement une tonne de données. Je ne m'inquiète pas de l'initialisation des données dans le fichier (le protocole que j'utilise - bittorrent - fournit des hachages pour les fichiers qu'il envoie, donc le pire des cas pour des données non initialisées aléatoires est une coïncidence chanceuse et une partie du fichier est correct).

Répondre

23

FileStream.SetLength est celui que vous voulez. La syntaxe:

public override void SetLength(
    long value 
) 
+1

ouais, c'est plus simple que ma solution :-) – Mark

5

Si vous devez créer le fichier, je pense que vous pouvez probablement faire quelque chose comme ceci:

using (FileStream outFile = System.IO.File.Create(filename)) 
{ 
    outFile.Seek(<length_to_write>-1, SeekOrigin.Begin); 
    OutFile.WriteByte(0); 
} 

Où length_to_write serait la taille en octets du fichier à écrire. Je ne suis pas sûr que j'ai la syntaxe C# correcte (pas sur un ordinateur pour tester), mais j'ai fait des choses similaires en C++ dans le passé et cela a fonctionné.

+0

Presque fonctionne. Vous devez chercher à moins écrire un octet, sinon vous finissez avec un fichier 0B. Toujours très utile, merci! Corrigez la syntaxe aussi. Si vous voulez éditer, la ligne supplémentaire dont vous avez besoin est OutFile.WriteByte (0); –

+0

corrigé par commentaire précédent – Mark

1

Malheureusement, vous ne pouvez pas vraiment le faire simplement en cherchant à la fin. Cela définira la longueur du fichier à quelque chose d'énorme, mais ne peut pas réellement allouer des blocs de disque pour le stockage. Donc, quand vous allez écrire le fichier, il échouera toujours.