Comment : utiliser la fonction ReadFile de Windows (Guide de programmation C#)

 

Cet exemple illustre la fonction ReadFile de Windows en lisant et affichant un fichier texte. La fonction ReadFile nécessite l'utilisation de code unsafe, car elle requiert un pointeur comme paramètre.

Le tableau d'octets passé à la fonction Read est un type managé. Cela signifie que le garbage collector de common language runtime (CLR) pourrait déplacer la mémoire utilisée par le tableau. Pour empêcher ceci, fixed est utilisé pour obtenir un pointeur vers la mémoire et le marquer afin que le garbage collector ne le déplace pas. À la fin du bloc fixed, la mémoire est automatiquement retournée à un état susceptible d'être soumis à parcourir le garbage collection.

Cette fonction est désignée par le terme « épinglage déclaratif ». L'épinglage est intéressant parce qu'il nécessite très peu de traitement supplémentaire sauf si une opération de garbage collection doit s'opérer sur le bloc fixed, ce qui est peu probable. Toutefois, l'épinglage peut mener à quelques effets secondaires indésirables pendant l'exécution du garbage collection global. La capacité du garbage collector de condenser la mémoire est limitée grandement par les mémoires tampons épinglées. Par conséquent, l'épinglage doit être évité si possible.

Exemple

class FileReader
{
    const uint GENERIC_READ = 0x80000000;
    const uint OPEN_EXISTING = 3;
    System.IntPtr handle;

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
    static extern unsafe System.IntPtr CreateFile
    (
        string FileName,          // file name
        uint DesiredAccess,       // access mode
        uint ShareMode,           // share mode
        uint SecurityAttributes,  // Security Attributes
        uint CreationDisposition, // how to create
        uint FlagsAndAttributes,  // file attributes
        int hTemplateFile         // handle to template file
    );

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
    static extern unsafe bool ReadFile
    (
        System.IntPtr hFile,      // handle to file
        void* pBuffer,            // data buffer
        int NumberOfBytesToRead,  // number of bytes to read
        int* pNumberOfBytesRead,  // number of bytes read
        int Overlapped            // overlapped buffer
    );

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
    static extern unsafe bool CloseHandle
    (
        System.IntPtr hObject // handle to object
    );

    public bool Open(string FileName)
    {
        // open the existing file for reading       
        handle = CreateFile
        (
            FileName,
            GENERIC_READ,
            0,
            0,
            OPEN_EXISTING,
            0,
            0
        );

        if (handle != System.IntPtr.Zero)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public unsafe int Read(byte[] buffer, int index, int count)
    {
        int n = 0;
        fixed (byte* p = buffer)
        {
            if (!ReadFile(handle, p + index, count, &n, 0))
            {
                return 0;
            }
        }
        return n;
    }

    public bool Close()
    {
        return CloseHandle(handle);
    }
}

class Test
{
    static int Main(string[] args)
    {
        if (args.Length != 1)
        {
            System.Console.WriteLine("Usage : ReadFile <FileName>");
            return 1;
        }

        if (!System.IO.File.Exists(args[0]))
        {
            System.Console.WriteLine("File " + args[0] + " not found.");
            return 1;
        }

        byte[] buffer = new byte[128];
        FileReader fr = new FileReader();

        if (fr.Open(args[0]))
        {
            // Assume that an ASCII file is being read.
            System.Text.ASCIIEncoding Encoding = new System.Text.ASCIIEncoding();

            int bytesRead;
            do
            {
                bytesRead = fr.Read(buffer, 0, buffer.Length);
                string content = Encoding.GetString(buffer, 0, bytesRead);
                System.Console.Write("{0}", content);
            }
            while (bytesRead > 0);

            fr.Close();
            return 0;
        }
        else
        {
            System.Console.WriteLine("Failed to open requested file");
            return 1;
        }
    }
}

Voir aussi

Guide de programmation C#
Référence C#
Pointeurs et code unsafe (Guide de programmation C#)
Types pointeur (Guide de programmation C#)
Garbage Collection