2012-10-31 9 views
43

मैं निम्नलिखित कोड,Async फ़ाइलों को कैसे करें। रीडअललाइन और परिणामों के लिए प्रतीक्षा करें?

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     button1.IsEnabled = false; 

     var s = File.ReadAllLines("Words.txt").ToList(); // my WPF app hangs here 
     // do something with s 

     button1.IsEnabled = true; 
    } 

Words.txt शब्द जो मैं रों चर में पढ़ा की एक टन है, मैं सी # में async और await खोजशब्दों का उपयोग 5 का उपयोग कर Async CTP Library तो WPF अनुप्रयोग नहीं करता है बनाने के लिए कोशिश कर रहा हूँ है लटका नहीं है। अब तक मैं निम्नलिखित कोड है,

private async void button1_Click(object sender, RoutedEventArgs e) 
    { 
     button1.IsEnabled = false; 

     Task<string[]> ws = Task.Factory.FromAsync<string[]>(
      // What do i have here? there are so many overloads 
      ); // is this the right way to do? 

     var s = await File.ReadAllLines("Words.txt").ToList(); // what more do i do here apart from having the await keyword? 
     // do something with s 

     button1.IsEnabled = true; 
    } 

लक्ष्य async में नहीं बल्कि सिंक से फ़ाइल को पढ़ने के लिए, WPF अनुप्रयोग के ठंड से बचने के लिए है।

किसी भी मदद की सराहना की है, धन्यवाद!

+1

अनावश्यक कॉल को ToList() से हटाकर शुरू करने के बारे में क्या है जो स्ट्रिंग सरणी की एक प्रति बना देगा? –

+2

@ जेबीईवेन - पैडेंटिक होने के लिए, 'ToList()' केवल सरणी की प्रतिलिपि नहीं करता है, यह 'सूची' बनाता है। अधिक जानकारी के बिना आप इसकी अनावश्यक नहीं मान सकते हैं, शायद "' // कुछ के साथ कुछ करें "कॉल 'सूची' विधियों। – Mike

उत्तर

80

अद्यतन: File.ReadAll[Lines|Bytes|Text], File.AppendAll[Lines|Text] और File.WriteAll[Lines|Bytes|Text] की Async संस्करणों अब merged into .NET Core किया गया है। इन विधियों को उम्मीद है कि .NET Framework, मोनो आदि पर वापस पोर्ट किया जाएगा और .NET मानक के भविष्य के संस्करण में घुमाया जाएगा।

Task.Run का उपयोग करना, जो अनिवार्य रूप से Task.Factory.StartNew के लिए एक रैपर है, एसिंक्रोनस रैपर is a code smell के लिए।

आप एक अवरुद्ध फ़ंक्शन का उपयोग करके एक सीपीयू धागा बर्बाद नहीं करना चाहते हैं, तो आप वास्तव में एक अतुल्यकालिक आईओ विधि, StreamReader.ReadToEndAsync, इस तरह का इंतजार करना चाहिए:

using (var reader = File.OpenText("Words.txt")) 
{ 
    var fileText = await reader.ReadToEndAsync(); 
    // Do something with fileText... 
} 

यह एक के रूप में पूरी फ़ाइल मिल जाएगा के बजाय string। आप के बजाय लाइनों की जरूरत है, आप आसानी से बाद में स्ट्रिंग विभाजित कर सकता है, इस तरह:

using (var reader = File.OpenText("Words.txt")) 
{ 
    var fileText = await reader.ReadToEndAsync(); 
    return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None); 
} 

संपादित: यहाँ कुछ तरीकों File.ReadAllLines रूप में एक ही कोड प्राप्त करने के लिए कर रहे हैं, लेकिन वास्तव में एक अतुल्यकालिक तरीके से। कोड File.ReadAllLines खुद के कार्यान्वयन पर आधारित है:

using System.Collections.Generic; 
using System.IO; 
using System.Text; 
using System.Threading.Tasks; 

public static class FileEx 
{ 
    /// <summary> 
    /// This is the same default buffer size as 
    /// <see cref="StreamReader"/> and <see cref="FileStream"/>. 
    /// </summary> 
    private const int DefaultBufferSize = 4096; 

    /// <summary> 
    /// Indicates that 
    /// 1. The file is to be used for asynchronous reading. 
    /// 2. The file is to be accessed sequentially from beginning to end. 
    /// </summary> 
    private const FileOptions DefaultOptions = FileOptions.Asynchronous | FileOptions.SequentialScan; 

    public static Task<string[]> ReadAllLinesAsync(string path) 
    { 
     return ReadAllLinesAsync(path, Encoding.UTF8); 
    } 

    public static async Task<string[]> ReadAllLinesAsync(string path, Encoding encoding) 
    { 
     var lines = new List<string>(); 

     // Open the FileStream with the same FileMode, FileAccess 
     // and FileShare as a call to File.OpenText would've done. 
     using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, DefaultOptions)) 
     using (var reader = new StreamReader(stream, encoding)) 
     { 
      string line; 
      while ((line = await reader.ReadLineAsync()) != null) 
      { 
       lines.Add(line); 
      } 
     } 

     return lines.ToArray(); 
    } 
} 
+0

मुझे इस धन्यवाद के बारे में पता नहीं था :) –

+6

यह महत्वपूर्ण रूप से किसी भी सीपीयू थ्रेड के बिना इसका इंतजार करने के लिए विंडोज I/O बंदरगाहों का उपयोग करता है, जबकि कार्य। फैक्टरी। स्टार्टन्यू/टास्क। अन्य जवाब में रून दृष्टिकोण एक सीपीयू थ्रेड को बर्बाद कर देता है। यह उत्तर का दृष्टिकोण अधिक कुशल है। –

+1

एफवाईआई; मैंने https://github.com/dotnet/corefx/issues/11220 पर इन एपीआई के एसिंक संस्करणों का प्रस्ताव दिया है। चलो देखते हैं कि यह कैसे जाता है :) – khellang

-3

इस प्रयास करें:

private async void button1_Click(object sender, RoutedEventArgs e) 
{ 
    button1.IsEnabled = false; 
    try 
    { 
     var s = await Task.Run(() => File.ReadAllLines("Words.txt").ToList()); 
     // do something with s 
    } 
    finally 
    { 
     button1.IsEnabled = true; 
    } 
} 

संपादित करें:

इस काम करने के लिए आप कोशिश अंत में जरूरत नहीं है। यह वास्तव में केवल एक पंक्ति है जिसे आपको बदलने की जरूरत है। यह बताने के लिए कि यह कैसे काम करता है: यह एक और धागा पैदा करता है (वास्तव में थ्रेड पूल से एक प्राप्त करता है) और वह धागा फ़ाइल को पढ़ने के लिए मिलता है। जब फ़ाइल पढ़ना समाप्त हो जाता है तो परिणाम के साथ बटन 1_Click विधि का शेष (जीयूआई थ्रेड से) कहा जाता है। ध्यान दें कि यह शायद सबसे कुशल समाधान नहीं है, लेकिन यह शायद आपके कोड में सबसे सरल परिवर्तन है जो जीयूआई को अवरुद्ध नहीं करता है।

+0

एक आकर्षण की तरह काम किया !!! धन्यवाद माइक, मैं 'टास्क.फैक्टरी.स्टार्टन्यू (() => 'कुछ कार्य') को अन्य कार्यों के लिए भी लागू करने में सक्षम था, फिर से धन्यवाद :) –

+10

हालांकि यह निश्चित रूप से सबसे आसान समाधान है और यह संभवतः काफी अच्छा होगा एक साधारण जीयूआई अनुप्रयोग के लिए, यह 'async' का उपयोग अपनी पूर्ण क्षमता में नहीं करता है, क्योंकि यह अभी भी धागे को अवरुद्ध करता है। – svick

+0

इसके अलावा, आप 'Task.Run()' का उपयोग करके अपना कोड छोटा कर सकते हैं। – svick

-3

मुझे आपके प्रश्न में वर्णित एक समस्या का भी सामना करना पड़ा। मैंने इसे हल किया है कि पिछले उत्तरों में:

string[] values; 
StorageFolder folder = ApplicationData.Current.LocalFolder; // Put your location here. 
IList<string> lines = await FileIO.ReadLinesAsync(await folder.GetFileAsync("Words.txt");); 
lines.CopyTo(values, 0); 
+0

कक्षाएं 'एप्लिकेशनडेटा' और 'फाइलियो' कहां से आती हैं? वे नेट फ्रेमवर्क का हिस्सा नहीं लगते हैं। 'एप्लिकेशनडेटा' [यूडब्ल्यूपी फ्रेमवर्क] (https://docs.microsoft.com/en-us/uwp/api/windows.storage.applicationdata) से प्रतीत होता है। इसका मतलब है कि आप "सामान्य" .NET अनुप्रयोग में 'एप्लिकेशनडेटा' का उपयोग नहीं कर सकते हैं। 'FileIO' [VisualBasic असेंबली] में मौजूद है (https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.filesystem (v = vs.110) .aspx), लेकिन इसमें नहीं है जहां तक ​​मैं देख सकता हूं async विधियां, तो आप इसे कहां से प्राप्त कर रहे हैं? – AndyJ

+0

@ एंडीजे, हाँ मेरा समाधान यूडब्ल्यूपी अनुप्रयोगों के लिए है। –

संबंधित मुद्दे