Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I started to learn about async programming and I stumbled across this problem. I call these functions over an Dispatcher.BeginInvoke.
I'm expecting to get file content form ReadText method, but all I get back is "System.Threading.Tasks.Task`1[System.String]"
So question is what's wrong with my code and which line should I fix?
Sadly I can't figure out where my problem is because I am looking at this peace of code for quite some time now.
I thought because I get back the time of the object and not the object itself that my ReadText method is wrong, but I don't see where. It seems there is something wrong with my part below the Stringbuilder or the way I made these methods async.
If you wonder why I used two methods is to get known with await and calling async Task methods. I also tried making the method a Tast method but that only resulted in even more problems.
Thanks for your help in advance.
public async void ReadFile()
{
string filePath = #"SampleFile.txt";
if (File.Exists(filePath) == false)
{
MessageBox.Show(filePath + " not found", "File Error", MessageBoxButton.OK);
}
else
{
try
{
string text = await ReadText(filePath);
txtContents.Text = text;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
private async Task<string> ReadText(string filePath)
{
Task Readfile = Task.Run(() =>
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true))
{
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[0x1000];
int numRead;
while ((numRead = sourceStream.Read(buffer, 0, buffer.Length)) != 0)
{
string text = Encoding.Unicode.GetString(buffer, 0, numRead);
sb.Append(text);
}
return sb.ToString();
}
}
);
await Readfile;
return Readfile.ToString();
}
You are returning a string, so make Readfile a Task<string>:
Task<string> Readfile = Task.Run<string>( ... )
Then you want to return Readfile.Result;, not Readfile.ToString();
But you can write this simpler:
return await Readfile;
or even:
return await Task.Run<string>( ... )
You don't need to use Task.Run for reading from the stream, there is convenient method ReadAsync that you can await:
public async Task ReadFile() {
string filePath = #"SampleFile.txt";
if (File.Exists(filePath) == false) {
MessageBox.Show(filePath + " not found", "File Error", MessageBoxButton.OK);
} else {
try {
string text = await ReadText(filePath);
txtContents.Text = text;
} catch (Exception ex) {
Debug.WriteLine(ex.Message);
}
}
}
private async Task<string> ReadText(string filePath) {
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true)) {
StringBuilder 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();
}
}
Also avoid async void is not recommended, try to avoid that.Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.
Best practice for async methods
Related
Using C# 10 I am creating Stream extensions to get content into a String or Byte array.
Something similar to File.ReadAllTextAsync in Microsoft's Net 6.
public static async Task<string> ReadAllTextAsync(this Stream stream). {
string result;
using (var reader = new StreamReader(stream)) {
result = await reader.ReadToEndAsync().ConfigureAwait(false);
}
return result;
}
public static async Task<byte[]> ReadAllBytesAsync(this Stream stream) {
using (var content = new MemoryStream()) {
var buffer = new byte[4096];
int read = await stream.ReadAsync(buffer, 0, 4096).ConfigureAwait(false);
while (read > 0) {
content.Write(buffer, 0, read);
read = await stream.ReadAsync(buffer, 0, 4096).ConfigureAwait(false);
}
return content.ToArray();
}
}
public static async Task<List<string>> ReadAllLinesAsync(this Stream stream) {
var lines = new List<string>();
using (var reader = new StreamReader(stream)) {
string line;
while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null) {
lines.Add(line);
}
}
return lines;
}
Is there a better way to do this?
I am not sure about the ConfigureAwait(false) that I picked on some code online.
A better alternative for the ReadAllBytesAsync is
public static async Task<byte[]> ReadAllBytesAsync(this Stream stream)
{
switch (stream)
{
case MemoryStream mem:
return mem.ToArray();
default:
using var m = new MemoryStream();
await stream.CopyToAsync(m);
return mem.ToArray();
}
}
For the ReadAllLinesAsync, the async stream in C# 8 can make the code cleaner:
public IAsyncEnumerable<string> ReadAllLinesAsync(this Stream stream)
{
using var reader = new StreamReader(stream)
while (await reader.ReadLineAsync() is { } line)
{
yield return line;
}
}
notice that the empty brace { } here is actually a property pattern that is only available after C# 8, it checks whether reader.ReadLineAsync() is null, if it's not, assign it to the line variable.
Usage:
var lines = await stream.ReadAllLinesAsync();
await foreach (var line in lines)
{
// write your own logic here
}
P.S.:
The ConfigureAwait(false) is kinda useless if your app is single-threaded like console apps, it instructs the awaiter not to capture the SynchronizationContext and let continuation run on the thread that runs the await statement, this method is useful when you're writing a library or SDK, since your user may use your library in a GUI application, and the combination of block waiting such as calling Task.Wait() and the capturing of SynchronizationContext often leads to deadlock, and ConfigureAwait(false) solves this. For detail explanation see ConfigureAwait FAQ
So, i'm trying to convert a large byte array into it's base64 encoded variant. But no matter what i try, it seems to freeze up my UI every time it runs.
This is what i've got currently:
private async void TxtOutput_DragDrop(object sender, DragEventArgs e)
{
string outputText = String.Empty;
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] path = (string[])e.Data.GetData(DataFormats.FileDrop);
byte[] fileBytes = File.ReadAllBytes(path[0]);
txtOutput.Text = await Task.Run(() => {return Convert.ToBase64String(fileBytes);});
_ = fileBytes;
_ = path;
}
}
So, the line that freezes everything up is:
txtOutput.Text = await Task.Run(() => {return Convert.ToBase64String(fileBytes);});
File.ReadAllBytes(path[0])
Could be a bottle neck you can use async operation for read files
Here is an example how to read file async
public async Task ProcessReadAsync()
{
string filePath = #"temp2.txt";
if (File.Exists(filePath) == false)
{
Debug.WriteLine("file not found: " + filePath);
}
else
{
try
{
string text = await ReadTextAsync(filePath);
Debug.WriteLine(text);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
private async Task<string> ReadTextAsync(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true))
{
StringBuilder 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();
}
}
Right, so it turns out that my problem was using a textbox for writing the string to instead of a richtextbox. This fixed my problem. Thanks for your answers.
I am attempting to search files for specific text using an async Task. The output I receive is in chinese characters instead of what is actually in the text file I am parsing. Here is the code:
public async void ProcessRead(string fileLocation)
{
string filePath = fileLocation;
if (File.Exists(filePath) == false)
{
Debug.WriteLine("file not found: " + filePath);
}
else
{
try
{
string text = await ReadTextAsync(filePath);
Debug.WriteLine(text);
if (text.Contains(inputContentPattern))
{
addToDataGrid(Path.GetFileName(filePath), filePath, "");
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
findButton.Enabled = true;
cancelFindButton.Enabled = false;
}
private async Task<string> ReadTextAsync(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true))
{
StringBuilder 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();
}
}
You are reading the file using Unicode encoding (in an incorrect way). Find out what encoding the file actually has and use that encoding. Simply use File.ReadAllText and delete ReadTextAsync.
Async IO brings you zero performance benefits here so just don't do it. If this is a UI app use await Task.Run(() => File.ReadAllText(...)).
How can I modify this method to call it asynchronously?
private void Write(string fileName, data)
{
File.WriteAllText(fileName, data);
}
Look into FileStream.WriteAsync (Note you have to use the proper overload which takes a bool indicating if it should run async:)
public async Task WriteAsync(string data)
{
var buffer = Encoding.UTF8.GetBytes(data);
using (var fs = new FileStream(#"File", FileMode.OpenOrCreate,
FileAccess.Write, FileShare.None, buffer.Length, true))
{
await fs.WriteAsync(buffer, 0, buffer.Length);
}
}
Edit
If you want to use your string data and avoid the transformation to a byte[], you can use the more abstracted and less verbose StreamWriter.WriteAsync overload which accepts a string:
public async Task WriteAsync(string data)
{
using (var sw = new StreamWriter(#"FileLocation"))
{
await sw.WriteAsync(data);
}
}
With .NetCore 2.0 you can just use File.WriteAllTextAsync
I have a problem on a few systems that when we are trying to load the RichTextBox the program becomes unresponsive, we cannot do anything and will have to kill it via Taskmanager.
its working on most systems but a few systems located in a different country there seems to be problem.
we have tried something as simple as :
private void testing4()
{
richTextBox1.LoadFile(#"C:\testing.logs", RichTextBoxStreamType.PlainText);
}
If we decide to use a normal TextBox it appears to be working using .net 4.5, but it still becomes unresponsive. Any ideas?
This may help you:
foreach(var line in File.ReadLines(#"C:\testing.logs"))
{
richTextBox1.AppendText(line+Environment.NewLine);
}
Since you are using framework 4.5, you can do it async, as in MSDN example:
public async void ReadFile()
{
string filePath = #"C:\testing.logs";
if (File.Exists(filePath) == false)
{
Debug.WriteLine("file not found: " + filePath);
}
else
{
try
{
string text = await ReadTextAsync(filePath);
richTextBox1.AppendText(text);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
private async Task<string> ReadTextAsync(string filePath)
{
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true))
{
StringBuilder 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();
}
}
Source: Using Async for File Access