Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Genom att använda funktionen async för att komma åt filer kan du anropa till asynkrona metoder utan att använda motringningar eller dela upp koden mellan flera metoder eller lambda-uttryck. Om du vill göra synkron kod asynkron anropar du en asynkron metod i stället för en synkron metod och lägger till några nyckelord i koden.
Överväg att lägga till asynkron till filåtkomstanrop av följande skäl:
- Asynkron gör UI-program mer dynamiska eftersom användargränssnittstråden som startar åtgärden kan utföra annat arbete. Om användargränssnittstråden måste köra kod som tar lång tid (till exempel mer än 50 millisekunder) kan användargränssnittet låsas tills I/O har slutförts och användargränssnittstråden kan bearbeta tangentbords- och musindata och andra händelser igen.
- Asynkron förbättrar skalbarheten för ASP.NET och andra serverbaserade program genom att minska behovet av trådar. Om programmet använder en dedikerad tråd per svar och tusen begäranden hanteras samtidigt behövs tusen trådar. Asynkrona åtgärder behöver ofta inte använda en tråd under väntan. De använder den befintliga I/O-slutförandetråden en kort stund i slutet.
- Svarstiden för en filåtkomståtgärd kan vara mycket låg under aktuella förhållanden, men svarstiden kan öka avsevärt i framtiden. En fil kan till exempel flyttas till en server som finns över hela världen.
- Den extra kostnaden för att använda Async-funktionen är liten.
- Flera asynkrona I/O-åtgärder kan köras utan att blockera den anropande tråden.
Använda lämpliga klasser
De enkla exemplen i det här avsnittet visar File.WriteAllTextAsync och File.ReadAllTextAsync. För fin kontroll över fil-I/O-åtgärder använder du FileStream klassen, som har ett alternativ som gör att asynkron I/O inträffar på operativsystemnivå. Med det här alternativet kan du undvika att blockera en trådpoolstråd i många fall. Om du vill aktivera det här alternativet anger du useAsync=true argumentet eller options=FileOptions.Asynchronous i konstruktoranropet.
Du kan inte använda det här alternativet med StreamReader och StreamWriter om du öppnar dem direkt genom att ange en filsökväg. Du kan dock använda det här alternativet om du tillhandahåller en Stream som har öppnats av FileStream-klassen. Asynkrona anrop går snabbare i användargränssnittsappar även om en trådpoolstråd blockeras, eftersom användargränssnittstråden inte blockeras under väntan.
Skriva text
I följande exempel skrivs text till en fil. Vid varje await-instruktion avslutas metoden omedelbart. När fil-I/O är klar återupptas metoden vid instruktionen som följer inväntningsuttryck. Asynkron modifieraren finns i definitionen av metoder som använder await-instruktionen.
Enkelt exempel
public async Task SimpleWriteAsync()
{
string filePath = "simple.txt";
string text = $"Hello World";
await File.WriteAllTextAsync(filePath, text);
}
Exempel på ändlig kontroll
public async Task ProcessWriteAsync()
{
string filePath = "temp.txt";
string text = $"Hello World{Environment.NewLine}";
await WriteTextAsync(filePath, text);
}
async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using var sourceStream =
new FileStream(
filePath,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
Det ursprungliga exemplet har -instruktionen await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);, som är en kontraktion av följande två instruktioner:
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
await theTask;
Den första instruktionen returnerar en uppgift och gör att filbearbetningen startar. Den andra instruktionen med await gör att metoden omedelbart avbryts och returnerar en annan uppgift. När filbearbetningen senare slutförs återgår exekveringen till instruktionen som följer efter await.
Läsa text
Följande exempel läser text från en fil.
Enkelt exempel
public async Task SimpleReadAsync()
{
string filePath = "simple.txt";
string text = await File.ReadAllTextAsync(filePath);
Console.WriteLine(text);
}
Exempel på ändlig kontroll
Texten buffras och placeras i det här fallet i en StringBuilder. Till skillnad från i föregående exempel genererar utvärderingen av await ett värde. Metoden ReadAsync returnerar en Task<Int32>, så utvärderingen av await genererar ett Int32 värde numRead när åtgärden har slutförts. Mer information finns i Async Return Types (C#).
public async Task ProcessReadAsync()
{
try
{
string filePath = "temp.txt";
if (File.Exists(filePath) != false)
{
string text = await ReadTextAsync(filePath);
Console.WriteLine(text);
}
else
{
Console.WriteLine($"file not found: {filePath}");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
async Task<string> ReadTextAsync(string filePath)
{
using var sourceStream =
new FileStream(
filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true);
var sb = new StringBuilder();
byte[] buffer = new byte[0x1000];
int numRead;
while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
string text = Encoding.Unicode.GetString(buffer, 0, numRead);
sb.Append(text);
}
return sb.ToString();
}
Flera asynkrona I/O-åtgärder
Följande exempel startar flera asynkrona skrivåtgärder. Körtiden köar dessa åtgärder, och den underliggande implementeringen kan använda asynkron I/O för operativsystem eller trådpooltrådar beroende på plattform och konfiguration, så den faktiska samtidigheten beror på det operativsystem och den maskinvara som används.
Enkelt exempel
public async Task SimpleParallelWriteAsync()
{
string folder = Directory.CreateDirectory("tempfolder").Name;
IList<Task> writeTaskList = new List<Task>();
for (int index = 11; index <= 20; ++ index)
{
string fileName = $"file-{index:00}.txt";
string filePath = $"{folder}/{fileName}";
string text = $"In file {index}{Environment.NewLine}";
writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
}
await Task.WhenAll(writeTaskList);
}
Exempel på ändlig styrning
För varje fil WriteAsync returnerar metoden en uppgift som läggs till i en lista över aktiviteter.
await Task.WhenAll(tasks); instruktionen avslutar metoden och fortsätter inom metoden när filbearbetningen är klar för alla uppgifter.
Exemplet stänger alla FileStream instanser i ett finally block när uppgifterna har slutförts. Om varje FileStream i stället skapas genom en using-instruktion, kan FileStream avvecklas innan uppgiften är slutförd.
Den asynkrona metoden undviker blockering av den tråd som gör anropet medan I/O är i vänteläge. I många fall beror dataflödesförbättringar på operativsystemet, maskinvaran och, på vissa plattformar, .NET-körningsbeteende, till exempel begränsningar för trådpooler och schemaläggning.
public async Task ProcessMultipleWritesAsync()
{
IList<FileStream> sourceStreams = new List<FileStream>();
try
{
string folder = Directory.CreateDirectory("tempfolder").Name;
IList<Task> writeTaskList = new List<Task>();
for (int index = 1; index <= 10; ++ index)
{
string fileName = $"file-{index:00}.txt";
string filePath = $"{folder}/{fileName}";
string text = $"In file {index}{Environment.NewLine}";
byte[] encodedText = Encoding.Unicode.GetBytes(text);
var sourceStream =
new FileStream(
filePath,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
sourceStreams.Add(sourceStream);
writeTaskList.Add(writeTask);
}
await Task.WhenAll(writeTaskList);
}
finally
{
foreach (FileStream sourceStream in sourceStreams)
{
sourceStream.Close();
}
}
}
När du använder metoderna WriteAsync och ReadAsync, kan du ange en CancellationToken för att avbryta åtgärden under processen. Mer information finns i Annullering i hanterade trådar.