44 votes

Écrire le fichier du flux de ressources d'assemblage sur le disque

Je n'arrive pas à trouver un moyen plus efficace de «copier» une ressource intégrée sur le disque, que ce qui suit:

 using (BinaryReader reader = new BinaryReader(
    assembly.GetManifestResourceStream(@"Namespace.Resources.File.ext")))
{
    using (BinaryWriter writer
        = new BinaryWriter(new FileStream(path, FileMode.Create)))
    {
        long bytesLeft = reader.BaseStream.Length;
        while (bytesLeft > 0)
        {
            // 65535L is < Int32.MaxValue, so no need to test for overflow
            byte[] chunk = reader.ReadBytes((int)Math.Min(bytesLeft, 65536L));
            writer.Write(chunk);

            bytesLeft -= chunk.Length;
        }
    }
}
 

Il ne semble pas y avoir de moyen plus direct de faire la copie, sauf si je manque quelque chose ...

67voto

Jon Skeet Points 692016

Je ne suis pas sûr de savoir pourquoi vous utilisez BinaryReader/BinaryWriter à tous. Personnellement, j'avais commencer avec un utilitaire méthode:

public static void CopyStream(Stream input, Stream output)
{
    // Insert null checking here for production
    byte[] buffer = new byte[8192];

    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}

puis l'appeler:

using (Stream input = assembly.GetManifestResourceStream(resourceName))
using (Stream output = File.Create(path))
{
    CopyStream(input, output);
}

Vous pouvez modifier la taille de la mémoire tampon de cours, ou de l'avoir en tant que paramètre à la méthode, mais le point principal est que c'est plus simple de code. Est-il plus efficace? Nope. Êtes-vous sûr que vous avez vraiment besoin de ce code pour être plus efficace? En effet, des centaines de méga-octets, vous devez écrire sur le disque?

J'ai trouver j'ai rarement besoin de code pour être ultra-efficace, mais j'ai presque toujours besoin d'être simple. Le genre de différence dans les performances que vous pouvez voir entre cela et un "sage" approche (si l'on est encore disponible) n'est pas susceptible d'être d'une complexité-modification de l'effet (par exemple, O(n) à O(log n)) - et c'est le type de gain de performance qui peut vraiment être intéressant la chasse.

EDIT: Comme indiqué dans les commentaires, les .NET 4.0 a Stream.CopyTo de sorte que vous n'avez pas besoin de code vous-même.

63voto

KoalaBear Points 653

Désolé que je poste sur un ancien fil, mais découvert un moyen encore plus facile si la ressource (fichier) est binaire.

 File.WriteAllBytes("C:\ResourceName", Resources.ResourceName);
 

22voto

cjbarth Points 838

En fait, j'ai fini par utiliser cette seule ligne: Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(New FileStream(FileLocation, FileMode.Create)) . Bien sûr, c'est pour .Net 4.0

Mise à jour: j'ai constaté que la ligne ci-dessus pouvait garder un fichier verrouillé de telle sorte que SQLite signale que la base de données est en lecture seule. Par conséquent, je me suis retrouvé avec ce qui suit:

 Using newFile As Stream = New FileStream(FileLocation, FileMode.Create)
    Assembly.GetExecutingAssembly().GetManifestResourceStream("[Project].[File]").CopyTo(newFile)
End Using
 

2voto

Lloyd Points 16334

Personnellement, je le ferais de cette façon:

 using (BinaryReader reader = new BinaryReader(
    assembly.GetManifestResourceStream(@"Namespace.Resources.File.ext")))
{
    using (BinaryWriter writer
        = new BinaryWriter(new FileStream(path, FileMode.Create)))
    {
        byte[] buffer = new byte[64 * 1024];
        int numread = reader.Read(buffer,0,buffer.Length);

        while (numread > 0)
        {
            writer.Write(buffer,0,numread);
            numread = reader.Read(buffer,0,buffer.Length);
        }

        writer.Flush();
    }
}
 

2voto

Henk Holterman Points 153608

Vous devrez écrire une boucle, si telle est votre question. Mais vous pourriez vous passer du lecteur et de l'écrivain car le Stream de base traite déjà des données d'octet [].

C'est à peu près aussi compact que possible:

 using (Stream inStream = File.OpenRead(inputFile))
using (Stream outStream = File.OpenWrite(outputFile))
{
    int read;
    byte[] buffer = new byte[64 * 1024];

    while ((read = inStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        outStream.Write(buffer, 0, read);
    }
}
 

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