Frage

Ich habe eine Dateiorganisator -Anwendung, an der ich arbeite. Die Dateien sind regelmäßig 500 MB bis 2 GB. Alles funktioniert gut, aber es ist äußerst ärgerlich, dass die Anwendung "nicht mehr reagiert". Was ich gerne tun würde, ist ein Byte von Byte oder Meg von Meg Copy mit einer Anwendung. Etwas in dieser Richtung, ich weiß nicht, was die tatsächlichen Klassen verwenden sollen, also werde ich einfach ein paar Sachen errichten :)

private void CopyFile(string inFilename, string outFilename)
{
    FileReader inReader(inFilename);
    FileWriter outWriter(outFilename, FileMode.OpenOrCreate);

    byte theByte;
    while (theByte = inReader.ReadByte())
    {
        outWriter.WriteByte(theByte, WriteMode.Append);
        UpdateProgressBar();
        Application.DoEvents();
    }

    inReader.CloseFile();
    outWriter.CloseFile();
}

Ich weiß, dass dies eine einfache Sache sein sollte, aber ich kann für das Leben von mir kein Beispiel dafür finden, dies ohne direkte API -Anrufe oder was auch immer zu tun. Ich muss hier etwas fehlen, also würde ich es wirklich zu schätzen wissen, wenn mich jemand hier auf den richtigen Weg bringen könnte.

Danke im Voraus!

War es hilfreich?

Lösung

Sie sollten a verwenden Hintergrundbearbeiter in Ihrem Formular, um das Kopieren zu machen. Damit können die Dateikopien in einem separaten Thread erfolgen und Ihre Benutzeroberfläche reagieren. Es gibt eine zusätzliche Komplexität, aber der Hintergrundarbeiter kümmert sich um viel Klempner für Sie. Aber es gibt viel von Beispiele von was willst du tun.

Andere Tipps

Sie müssen a verwenden Hintergrundworkerthread um das zu erreichen. Hier ist ein sehr gutes Beispiel dafür, wie das geht: Kopieren Sie die Datei mithilfe von Hintergrund -Worker -Threads

Ich würde das benutzen wollen CopyFileEx Funktion. Wenn eine Analogie zu dieser Funktion in der Managed Framework Library nicht vorhanden ist, dann für die Verwendung von Google, wie sie sie verwenden können: Vielleicht ein Artikel wie http://www.thetechscene.com/2008/09/copyFileex-with-progress-callback-in-c-using-pinvoke/

Mein Grund, verwenden zu wollen CopyFileEx Ich gehe davon aus, dass es im O/S -Kernel implementiert ist, wobei die Daten von einer Datei zu einer anderen im Dateisystem -Treiber kopieren, ohne Benutzerspeicher zu verwenden (geschweige denn verwaltete Speicher).

Threading.Threadpool.queueuserworkItem sollte Sie auf dem Weg machen.

Ein Ansatz besteht darin, die Kopieroperation in einem separaten Thread durchzuführen. Ihre Hauptanwendung wird weiterhin normal ausgeführt, während der Thread die Arbeit des Kopierens der Datei ausführt. Natürlich möchten Sie die Kommunikation zwischen dem Thread und der Hauptanwendung hinzufügen, damit Sie Ihren Fortschrittsbalken oder einen ähnlichen Feedback -Mechanismus aktualisieren können.

Wenn Sie sich lieber nicht mit mehreren Threads befassen möchten, besteht ein anderer Ansatz darin, eine Klasse zu erstellen, die Zustandsvariablen für die Kopieroperation und eine Mitgliedsfunktion enthält, die regelmäßig aus Ihrer Hauptanwendung aufgerufen wird, um eine bestimmte Anzahl von Bytes jedes Mal zu kopieren, wenn sie aufgerufen wird .

Neben dem Ausführen eines Hintergrund-Threads sollten Sie beachten, dass Sie 512 m-2g Daten kopieren ein Byte nach dem anderen. Dies wird sich in bis zu 2 übersetzen MILLIARDE Anrufe nach Readbyte und WriteByte. Hoffentlich haben diese Anrufe irgendwo Puffer, damit Sie nicht 2 machen MILLIARDE Es geschafft, nicht verwaltete Übergänge zu erfüllen, aber das summiert sich sicherlich.

Das Gedächtnis ist nicht kostenlos, aber es ist sicher, da Heck billig ist. Weisen Sie einen Puffer (vielleicht 16K-64K) und kopieren Sie in Stücken. Nein, der Code ist nicht so einfach, wie Sie einen Fall des Nicht -Lesens des gesamten Blocks abwickeln müssen, aber ich möchte lieber auf 2G -Methodenaufrufe über 2 g.

Sie haben hier zwei Probleme. Das erste ist, dass der GUI -Thread beim Kopieren großer Dateien nicht reagiert. Sie sollten einen Hintergrund -Thread verwenden, um dies zu lösen, wie andere vorgeschlagen haben.

Das andere Problem ist, dass Ihre aktuelle Routine zum Kopieren von Dateien keine Fortschritts -Rückruffunktion unterstützt. Die akzeptierte Antwort auf die folgende Frage enthält die Informationen, die Sie benötigen, um Ihre eigene Lösung zu schreiben:

Kann ich den Fortschritt des Dateikopierens mit FileInfo.copyto () in .NET kopieren?

Bearbeiten: Ich habe das gerade gefunden Wrapper -Klasse für CopyFileex. Ich habe es getestet und es funktioniert großartig!

using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;

namespace FileCopyTest {
    public sealed class FileRoutines {
        public static void CopyFile(FileInfo source, FileInfo destination) {
            CopyFile(source, destination, CopyFileOptions.None);
        }

        public static void CopyFile(FileInfo source, FileInfo destination,
            CopyFileOptions options) {
            CopyFile(source, destination, options, null);
        }

        public static void CopyFile(FileInfo source, FileInfo destination,
            CopyFileOptions options, CopyFileCallback callback) {
            CopyFile(source, destination, options, callback, null);
        }

        public static void CopyFile(FileInfo source, FileInfo destination,
            CopyFileOptions options, CopyFileCallback callback, object state) {
            if (source == null) throw new ArgumentNullException("source");
            if (destination == null)
                throw new ArgumentNullException("destination");
            if ((options & ~CopyFileOptions.All) != 0)
                throw new ArgumentOutOfRangeException("options");

            new FileIOPermission(
                FileIOPermissionAccess.Read, source.FullName).Demand();
            new FileIOPermission(
                FileIOPermissionAccess.Write, destination.FullName).Demand();

            CopyProgressRoutine cpr = callback == null ?
                null : new CopyProgressRoutine(new CopyProgressData(
                    source, destination, callback, state).CallbackHandler);

            bool cancel = false;
            if (!CopyFileEx(source.FullName, destination.FullName, cpr,
                IntPtr.Zero, ref cancel, (int)options)) {
                throw new IOException(new Win32Exception().Message);
            }
        }

        private class CopyProgressData {
            private FileInfo _source = null;
            private FileInfo _destination = null;
            private CopyFileCallback _callback = null;
            private object _state = null;

            public CopyProgressData(FileInfo source, FileInfo destination,
                CopyFileCallback callback, object state) {
                _source = source;
                _destination = destination;
                _callback = callback;
                _state = state;
            }

            public int CallbackHandler(
                long totalFileSize, long totalBytesTransferred,
                long streamSize, long streamBytesTransferred,
                int streamNumber, int callbackReason,
                IntPtr sourceFile, IntPtr destinationFile, IntPtr data) {
                return (int)_callback(_source, _destination, _state,
                    totalFileSize, totalBytesTransferred);
            }
        }

        private delegate int CopyProgressRoutine(
            long totalFileSize, long TotalBytesTransferred, long streamSize,
            long streamBytesTransferred, int streamNumber, int callbackReason,
            IntPtr sourceFile, IntPtr destinationFile, IntPtr data);

        [SuppressUnmanagedCodeSecurity]
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool CopyFileEx(
            string lpExistingFileName, string lpNewFileName,
            CopyProgressRoutine lpProgressRoutine,
            IntPtr lpData, ref bool pbCancel, int dwCopyFlags);
    }

    public delegate CopyFileCallbackAction CopyFileCallback(
        FileInfo source, FileInfo destination, object state,
        long totalFileSize, long totalBytesTransferred);

    public enum CopyFileCallbackAction {
        Continue = 0,
        Cancel = 1,
        Stop = 2,
        Quiet = 3
    }

    [Flags]
    public enum CopyFileOptions {
        None = 0x0,
        FailIfDestinationExists = 0x1,
        Restartable = 0x2,
        AllowDecryptedDestination = 0x8,
        All = FailIfDestinationExists | Restartable | AllowDecryptedDestination
    }
}

Was Sie wirklich tun möchten, ist eine multi-thread-Anwendung und die Dateikopie in einem Hintergrund-Thread durchzuführen. Auf diese Weise wird Ihr Haupt-Thread nicht gebunden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top