369 votes

Sauvegarde et chargement de MemoryStream vers/depuis un fichier

Je suis en train de sérialiser une structure dans un MemoryStream et je veux sauvegarder et charger la structure sérialisée.

Alors, comment sauver un MemoryStream dans un fichier et le charger à nouveau à partir du fichier ?

1 votes

Si vous avez besoin de sauvegarder dans un fichier, pourquoi utilisez-vous une MemoryStream ?

0 votes

@Oded Que dois-je utiliser ? Pouvez-vous me donner un exemple ?

439voto

AVD Points 57984

Vous pouvez utiliser MemoryStream.WriteTo ou Stream.CopyTo (supporté dans le framework version 4.5.2, 4.5.1, 4.5, 4) méthodes pour écrire le contenu d'un flux mémoire vers un autre flux.

memoryStream.WriteTo(fileStream);

Mise à jour :

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);

19 votes

MemoryStream.CopyTo ne semble pas fonctionner pour moi, alors que WriteTo fonctionne. Je pense que c'est peut-être parce que ma memoryStream.Position n'était pas à 0.

20 votes

Oui, c'est exact. La différence entre les deux est que CopyTo copie à partir de n'importe quelle position actuelle au lieu de toujours commencer au début comme WriteTo le fait.

13 votes

Ajout de [file|memory]Stream.Seek(0, SeekOrigin.Begin); avant CopyTo mettra la position actuelle à 0, de sorte que CopyTo copiera le flux complet.

325voto

En supposant que le nom du MemoryStream est ms .

Ce code écrit le MemoryStream dans un fichier :

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write)) {
   byte[] bytes = new byte[ms.Length];
   ms.Read(bytes, 0, (int)ms.Length);
   file.Write(bytes, 0, bytes.Length);
   ms.Close();
}

et ceci lit un fichier dans un MemoryStream :

using (MemoryStream ms = new MemoryStream())
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
   byte[] bytes = new byte[file.Length];
   file.Read(bytes, 0, (int)file.Length);
   ms.Write(bytes, 0, (int)file.Length);
}

Dans .Net Framework 4+, vous pouvez simplement copier FileStream vers MemoryStream et inversement, aussi simple que cela :

MemoryStream ms = new MemoryStream();
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read))
    file.CopyTo(ms);

Et l'inverse (MemoryStream vers FileStream) :

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);

1 votes

Puis-je vous demander pourquoi vous utilisez FileMode.Create dans l'échantillon lu plutôt que FileMode.Open ?

7 votes

Dans le premier bloc de code, au lieu de copier manuellement le flux de mémoire dans le tableau, vous pouvez utiliser le module intégré ms.ToArray() fonction.

9 votes

Il est important de définir ms.Position = 0, sinon le tableau d'octets (et le fichier) ne contiendra que des zéros.

77voto

Rob Church Points 1300

Le flux doit vraiment être éliminé même s'il y a une exception (très probablement lors d'une entrée/sortie de fichier) - les clauses d'utilisation sont mon approche préférée pour cela, donc pour écrire votre MemoryStream, vous pouvez utiliser :

using (FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write)) {
    memoryStream.WriteTo(file);
}

Et pour l'avoir relu :

using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
    byte[] bytes = new byte[file.Length];
    file.Read(bytes, 0, (int)file.Length);
    ms.Write(bytes, 0, (int)file.Length);
}

Si les fichiers sont volumineux, il convient de noter que l'opération de lecture utilisera deux fois plus de mémoire que la taille totale du fichier. . Une solution à cela est de créer le MemoryStream à partir du tableau d'octets - le code suivant suppose que vous n'écrirez pas ensuite dans ce flux.

MemoryStream ms = new MemoryStream(bytes, writable: false);

Mes recherches (ci-dessous) montrent que le tampon interne est le même tableau d'octets que celui que vous lui passez, ce qui devrait donc permettre d'économiser de la mémoire.

byte[] testData = new byte[] { 104, 105, 121, 97 };
var ms = new MemoryStream(testData, 0, 4, false, true);
Assert.AreSame(testData, ms.GetBuffer());

24voto

Berkay Points 1396

La réponse combinée pour l'écriture dans un fichier peut être ;

MemoryStream ms = new MemoryStream();    
FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
ms.Close();

18voto

ProVega Points 1425

Pour le chargement d'un fichier, j'aime beaucoup mieux ceci

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}

0 votes

Si un fichier est ouvert dans Microsoft Word, existe-t-il un moyen de créer un flux de mémoire à partir de ce fichier ? Je reçois une erreur "le fichier est ouvert par un autre processus".

0 votes

@FrenkyB Je rencontre aussi souvent ce problème. Si vous avez le fichier ouvert dans Word ou une autre application, vous ne pouvez pas le faire. Fermez simplement le fichier dans Word.

0 votes

@FrenkyB Pouvez-vous faire un File.Copy ? J'ai trouvé que cela fonctionnait, puis lire à partir de ce fichier dans un flux et supprimer le nouveau fichier ... horrible, mais semble fonctionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X