out
параметры инициализируются названным методом, ref
, параметры инициализируются прежде, чем назвать метод. Поэтому out
параметры используются, когда просто необходимо получить вторичное возвращаемое значение, ref
, параметры используются для получения значения , и потенциально возвращают изменение в том значении (во вторую очередь к основному возвращаемому значению).
File.Copy был построен вокруг функции Win32 CopyFile , и эта функция требует много внимания со стороны команды MS (вспомните эти связанные с Vista потоки о медленной производительности копирования).
Несколько подсказок для повышения производительности вашего метода:
Пример шаблона асинхронного копирования:
int Readed = 0;
IAsyncResult ReadResult;
IAsyncResult WriteResult;
ReadResult = sourceStream.BeginRead(ActiveBuffer, 0, ActiveBuffer.Length, null, null);
do
{
Readed = sourceStream.EndRead(ReadResult);
WriteResult = destStream.BeginWrite(ActiveBuffer, 0, Readed, null, null);
WriteBuffer = ActiveBuffer;
if (Readed > 0)
{
ReadResult = sourceStream.BeginRead(BackBuffer, 0, BackBuffer.Length, null, null);
BackBuffer = Interlocked.Exchange(ref ActiveBuffer, BackBuffer);
}
destStream.EndWrite(WriteResult);
}
while (Readed > 0);
Очистив отражатель от пыли, мы видим, что File.Copy фактически вызывает Win32 API:
if (!Win32Native.CopyFile(fullPathInternal, dst, !overwrite))
Что разрешается в
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool CopyFile(string src, string dst, bool failIfExists);
Вы никогда не сможете превзойти операционную систему, сделав что-то столь фундаментальное с вашим собственным кодом, даже если вы тщательно написали это на ассемблере.
Если вам нужно, убедитесь, чтобы ваши операции выполнялись с максимальной производительностью И вы хотите смешивать и сопоставлять различные источники, тогда вам нужно будет создать тип, описывающий расположение ресурсов. Затем вы создаете API, который имеет такие функции, как Копировать
, который принимает два таких типа и, изучив их описания, выбирает наиболее эффективный механизм копирования. Например, определив, что оба местоположения являются местоположениями файлов Windows, вы должны выбрать File.Copy ИЛИ, если источником является файл Windows, а местом назначения должен быть HTTP POST, он использует WebRequest.
Три изменения значительно улучшат производительность:
В экспериментах, которые я пробовал, это выглядело примерно в 3-4 раза быстрее:
public static void Copy(System.IO.Stream inStream, string outputFilePath)
{
int bufferSize = 1024 * 1024;
using (FileStream fileStream = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write))
{
fileStream.SetLength(inStream.Length);
int bytesRead = -1;
byte[] bytes = new byte[bufferSize];
while ((bytesRead = inStream.Read(bytes, 0, bufferSize)) > 0)
{
fileStream.Write(bytes, 0, bytesRead);
}
}
}
Попробуйте удалить вызов Flush и переместить его за пределы цикла.
Иногда ОС лучше знает, когда очищать данные ввода-вывода. Это позволяет лучше использовать внутренние буферы.
Вот аналогичный ответ
Как мне скопировать содержимое одного потока в другой?
Ваша основная проблема - это вызов Flush (), который свяжет вашу производительность с скорость ввода / вывода.
Марк Руссинович будет авторитетом по этому вопросу.
Он написал на своем blog запись Внутри Vista SP1 Улучшения копирования файлов , в которой резюмируется состояние Windows в Vista SP1.
Мое полуобразованное предположение было бы, что File.Copy будет наиболее надежным по сравнению с наибольшее количество ситуаций. Конечно, это не означает, что в каком-то конкретном угловом случае ваш собственный код может превзойти его ...
Одна вещь, которая выделяется, - это то, что вы читаете кусок, записываете этот кусок, читаете другой кусок и т. Д.
Потоковые операции - отличные кандидаты для многопоточности. Я предполагаю, что File.Copy реализует многопоточность.
Попробуйте читать в одном потоке и писать в другом. Вам нужно будет координировать потоки, чтобы поток записи не начал записывать буфер, пока поток чтения не завершит его заполнение. Вы можете решить эту проблему, имея два буфера, один из которых читается, а другой записывается, и флаг, указывающий, какой буфер в настоящее время используется для какой цели.