Можно ли "запустить" копию (большого) файла, не дожидаясь результата?
Я думаю, что это довольно очевидно в названии; Я хочу скопировать файл, не дожидаясь результата.
Функционально я хочу это:
static void Main(string[] args)
{
string strCmdText = @"/C xcopy c:\users\florian\desktop\mytestfile.fil p:\";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
Console.WriteLine("Finished !");
}
В основном мой основной поток освобождается через несколько миллисекунд. Я пытаюсь сделать так:
static void Main(string[] args)
{
var t = Task.Run(() => Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyToAsync(DestinationStream);
}
}
}
Мой mytestfile.fil создан в папке назначения, но его размер составляет 0 КБ.
С Уважением,
4 ответа
В основном мой основной поток освобождается через несколько миллисекунд. Я пытаюсь сделать так
Вы должны как-то поддерживать процесс. Самый простой способ сделать это - если вам действительно нужно сделать копию файла в отдельном потоке - это выполнить метод Copy в потоке переднего плана:
class Program
{
static void Main(string[] args)
{
System.Threading.Thread thread = new System.Threading.Thread(()=> Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
thread.Start();
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyTo(DestinationStream);
}
}
}
}
... или вы можете выполнить его в главном потоке, так как ваше приложение больше ни на что не похоже:
class Program
{
static void Main(string[] args)
{
string source = @"c:\Users\florian\Desktop\mytestfile.fil";
string destination = "p";
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyTo(DestinationStream);
}
}
}
}
Третий вариант - сделать ваш метод асинхронным и дождаться его синхронного завершения в методе Main:
class Program
{
static void Main(string[] args)
{
CopyAsync(@"c:\Users\florian\Desktop\mytestfile.fil", "p:").Wait();
}
private static async Task CopyAsync(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
await SourceStream.CopyToAsync(DestinationStream);
}
}
}
}
Обратите внимание, что вы не должны использовать асинхронный метод CopyToAsync, если вы его не ожидаете. Не смешивайте синхронный и асинхронный код:)
ОК, более одной ошибки.
- Ваша программа завершает работу до завершения копирования. вам нужно что-то вроде:
CopyToAsync не ожидался
class Program { private static void Main(string[] args) { var source = new CancellationTokenSource(); Console.CancelKeyPress += (s, e) => { e.Cancel = true; source.Cancel(); }; try { MainAsync(args, source.Token).GetAwaiter().GetResult(); return; } catch (OperationCanceledException) { return; } } static async Task MainAsync(string[] args, CancellationToken token) { var t = Task.Run(() => Copy(@"c:\test.txt", @"c:\dest\")); Console.WriteLine("doing more stuff while copying"); await t; Console.WriteLine("Finished !"); } private static void Copy(string source, string destination) { using (FileStream SourceStream = File.Open(source, FileMode.Open)) { using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\')))) { SourceStream.CopyTo(DestinationStream); } } }
}
Кажется, что это может быть примером проблемы XY.
Имейте в виду, что OS/framework в основном предоставляет вашему процессу свое "пространство" для запуска, поэтому следующее:
static void Main(string[] args)
{
var t = Task.Run(() => Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyToAsync(DestinationStream);
}
}
}
ничем не отличается с точки зрения производительности, чем просто делать
static void Main(string[] args)
{
Copy(@"c:\Users\florian\Desktop\mytestfile.fil", "p:");
}
Поскольку ваше консольное приложение принципиально не делает ничего, кроме копирования файла, дополнительный поток просто добавляет накладные расходы.
Кроме того, если вы используете асинхронные операции внутри метода Copy, вы должны объявить свой метод async Task
скорее, чем void
потому что в противном случае вы не можете использовать await
Ключевое слово внутри Copy
метод или ждать Copy
метод для завершения в другом месте в коде. Так:
private static async Task Copy(string source, string destination)
Как написано, это имеет явное состояние гонки и, вероятно, не будет работать правильно, потому что DestinationStream
а также SourceStream
могут быть утилизированы до SourceStream.CopyToAsync(DestinationStream)
на самом деле закончил. Вам нужно сделать
await SourceStream.CopyToAsync(DestinationStream);
внутри вашего метода, чтобы предотвратить это.
Если вы запускаете операцию копирования с
System.Diagnostics.Process.Start(...);
вы уже эффективно выполняете это асинхронно с точки зрения программы, которая запустила его, потому что программа, которая запустила его, не ждет завершения процесса, прежде чем он продолжится. Кстати, я предполагаю, что это консольное приложение будет делать что-то иное, чем просто запуск процесса, правильно? (Если нет, это кажется немного излишним).
Ваш метод Main возвращается до завершения задачи, поэтому ваше приложение заканчивается.