Filestream does not free file for other processes - c#

I have the following code to write a file. The problem is that if I want to overwrite the same file, it is "locked". The file is opened by another process.
using (FileStream fs = new FileStream("C:\\New\\" + fileName, FileMode.Create, FileAccess.ReadWrite))
using (StreamWriter str = new StreamWriter(fs))
{
str.Write(jsonFile);
str.Dispose();
str.Close();
}
I send a json string to an API, which then generates the file. So I guess it might be a problem in IIS.
EDIT:
By research I have still tried the following code, but which leads to the same result
using (FileStream fs = new FileStream("C:\\New\\" + fileName, FileMode.Create, FileAccess.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
sw.Write(jsonFile);
fs.Flush();
fs.Close();
}
EDIT 2:
After reading the comments, it probably has nothing to do with the Filestream to itself. Here is more information about my application:
I have a WPF application which sends a post to my API through a ButtonClick. This is triggered as follows:
private async void btnSend_Click(object sender, RoutedEventArgs e)
{
await Seal();
}
The Seal method says the following:
private async System.Threading.Tasks.Task Seal()
{
var result = await RequestManager.DoPost<bool>("FOO", foo);
}
The RequestManager says the following:
public static async Task<R> DoPost<R>(String route, Object payload, String contenttype)
{
var serializer = new JavaScriptSerializer();
route = route.StartsWith("/") ? route : "/" + route;
var content = new StringContent(serializer.Serialize(payload), Encoding.UTF8, contenttype);
var response = await client.PostAsync(RequestManager.API_URL + route, content);
if (response.StatusCode == HttpStatusCode.OK)
{
var result = await response.Content.ReadAsStringAsync();
return (R)serializer.Deserialize(result, typeof(R));
}
else
{
throw new ResponseException(response.StatusCode, response.Content.ReadAsStringAsync().Result);
}
}
I really do not know where my error is, or where the request must be closed.

This error could occur when multiple threads are attempting to write at the same file. Your code above works with a little modification
private static object lk = new object();
lock (lk)
{
using (FileStream fs = new FileStream("C:\\New\\" +fileName,FileMode.Create, FileAccess.ReadWrite))
using (StreamWriter str = new StreamWriter(fs))
{
str.Write(jsonFile);
str.Dispose();
str.Close();
}
}

Related

using WebClient UploadFile Thread was being aborted

When I write to a file and upload the same file to FTP site, I get Thread was being aborted error.
FileIoUtility.WriteDataToFile(skillsSummaryData, SkillSummaryFileLocation);
if (!IsFileLocked(SkillSummaryFileLocation))
{
using (WebClient myWebClient = new WebClient())
{
myWebClient.Credentials = new NetworkCredential(FtpUsername, FtpPassword);
var uri = new Uri($"{FtpHost}SkillSummary.txt", UriKind.RelativeOrAbsolute);
byte[] responseArray = myWebClient.UploadFile(uri, WebRequestMethods.Ftp.UploadFile,
SkillSummaryFileLocation);
var response = Encoding.ASCII.GetString(responseArray);
}
}
Here is my WriteDataToFile method:
public static void WriteDataToFile(string data, string fileLocation, bool append = false)
{
if (!File.Exists(fileLocation))
{
File.Create(fileLocation).Dispose();
}
lock (Locker)
{
using (FileStream file =
new FileStream(fileLocation, FileMode.Append, FileAccess.Write, FileShare.Read))
{
using (StreamWriter writer = new StreamWriter(file, Encoding.Unicode))
{
writer.Write(data);
}
}
}
}
If I skip the following line and run the upload then it works.
FileIoUtility.WriteDataToFile(skillsSummaryData, SkillSummaryFileLocation);
Exception doesn't give anything more than Thread was being aborted. How can I make this work?

MVC download file from API and retun as result

I have a requirement to pass a file through an MVC action method.
To download it from a Web API method and return it as a result.
The code I have is assembled from a few answers here on SO and some other references.
The problem is that the file seems to be locked by the download process when I try to return it as a result. I thought that the tsk.Wait() wold solve the problem.
Perhaps someone knows of a better solution?
using (var client = HttpClientProvider.GetHttpClient())
{
client.BaseAddress = new Uri(baseAddress);
await client.GetAsync("api/Documents/" + fileName).ContinueWith(
(requestTask) =>
{
HttpResponseMessage response = requestTask.Result;
response.EnsureSuccessStatusCode();
fileName = response.Content.Headers.ContentDisposition.FileName;
if (fileName.StartsWith("\"") && fileName.EndsWith("\""))
{
fileName = fileName.Trim('"');
}
if (fileName.Contains(#"/") || fileName.Contains(#"\"))
{
fileName = Path.GetFileName(fileName);
}
path = Path.Combine(GetDocsMapPath(), fileName);
System.Threading.Tasks.Task tsk = response.Content.ReadAsFileAsync(path, true).ContinueWith(
(readTask) =>
{
Process process = new Process();
process.StartInfo.FileName = path;
process.Start();
});
tsk.Wait();
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read));
resp.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
resp.Content.Headers.ContentDisposition.FileName = fileName;
return resp;
});
}
public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite)
{
string pathname = Path.GetFullPath(filename);
if (!overwrite && File.Exists(filename))
{
throw new InvalidOperationException(string.Format("File {0} already exists.", pathname));
}
FileStream fileStream = null;
try
{
fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None);
return content.CopyToAsync(fileStream).ContinueWith(
(copyTask) =>
{
fileStream.Close();
fileStream.Dispose();
});
}
catch
{
if (fileStream != null)
{
fileStream.Close();
fileStream.Dispose();
}
throw;
}
}
first, I don't see any useful function achieved by the process you launch, apart from locking your file, which you don't want.
try removing these lines and retrying.
.ContinueWith(
(readTask) =>
{
Process process = new Process();
process.StartInfo.FileName = path;
process.Start();
});
Edit: Using FilePathResult
I don't know about your exact requirements, but if your goal is to return a file that you have the path for; then the easiest is to return a FilePathResult which will take care of reading and returning the contents of the file to the requester.
public FilePathResult GetFile()
{
//put your logic to determine the file path here
string name = ComputeFilePath();
//verify that the file actually exists and retur dummy content otherwise
FileInfo info = new FileInfo(name);
if (!info.Exists)
{
using (StreamWriter writer = info.CreateText())
{
writer.WriteLine("File Not Found");
}
}
return File(name, "application/octet-stream");
}
if you are sure of what type your content is , change the mime type accordingly, otherwise it's better to leave it as a binary data.

Async method to read and write to XML file

I am using DependencyService in android/ios and windows phone to write and read a XML file in my Xamarin.forms project. I am referring to working with files.
I was able to implement the function given in the example but what I actually want is reading and writing to a XML file.
I followed a usual c# procedure to read and write to xml file but getting errors as the method is async.
I have never used async await methods so not sure how to go about it.
Here is what I tried:
public async Task SaveTextAsync(string filename, string text)
{
ApplicationData data = new ApplicationData();
ApplicationVersion version = new ApplicationVersion();
version.SoftwareVersion = "test";
data.ApplicationVersion = version;
XmlSerializer writer =
new XmlSerializer(typeof(ApplicationData));
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, data);
file.Close();
}
public async Task<string> LoadTextAsync(string filename)
{
var path = CreatePathToFile(filename);
ApplicationData cars = null;
XmlSerializer serializer = new XmlSerializer(typeof(ApplicationData));
StreamReader reader = new StreamReader(path);
cars = (ApplicationData)serializer.Deserialize(reader);
reader.Close();
}
string CreatePathToFile(string filename)
{
var docsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(docsPath, filename);
}
Edit
Working Read and write to txt file code is here:
public async Task SaveTextAsync (string filename, string text)
{
var path = CreatePathToFile (filename);
using (StreamWriter sw = File.CreateText (path))
await sw.WriteAsync(text);
}
public async Task<string> LoadTextAsync (string filename)
{
var path = CreatePathToFile (filename);
using (StreamReader sr = File.OpenText(path))
return await sr.ReadToEndAsync();
}
I managed to get it work. Here is my code:
public async Task SaveTextAsync(string filename)
{
var path = CreatePathToFile(filename);
ApplicationData data = new ApplicationData();
ApplicationVersion version = new ApplicationVersion();
version.SoftwareVersion = "test version";
data.ApplicationVersion = version;
XmlSerializer writer =
new XmlSerializer(typeof(ApplicationData));
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, data);
file.Close();
}
public async Task<ApplicationData> LoadTextAsync(string filename)
{
var path = CreatePathToFile(filename);
ApplicationData records = null;
await Task.Run(() =>
{
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new XmlSerializer(typeof(ApplicationData));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream(path, FileMode.Open);
XmlReader reader = XmlReader.Create(fs);
// Use the Deserialize method to restore the object's state.
records = (ApplicationData)serializer.Deserialize(reader);
fs.Close();
});
return records;
}

Writing to a file asynchronously

Is there any way to write an asynchronous function that writes to data to a file repeatedly.
I am getting the following error when I write asynchronous function
The process cannot access the file 'c:\Temp\Data.txt' because it is being used by another process
public void GoButton_Click(object sender, System.EventArgs e)
{
IAsyncResult ar = DoSomethingAsync(strURL, strInput);
Session["result"] = ar;
Response.Redirect("wait1.aspx");
}
private IAsyncResult DoSomethingAsync(string strURL, string strInput)
{
DoSomethingDelegate doSomethingDelegate = new DoSomethingDelegate(DoSomething);
IAsyncResult ar = doSomethingDelegate.BeginInvoke(strURL, strInput, new AsyncCallback(MyCallback), null);
return ar;
}
private delegate void DoSomethingDelegate(string strURL, string strInput);
private void MyCallback(IAsyncResult ar)
{
AsyncResult aResult = (AsyncResult)ar;
DoSomethingDelegate doSomethingDelegate = (DoSomethingDelegate)aResult.AsyncDelegate;
doSomethingDelegate.EndInvoke(ar);
}
private void DoSomething(string strURL, string strInput)
{
int i = 0;
for (i = 0; i < 1000; i++)
{
m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
m_streamWriter.WriteLine("{0} ", MethodCall(strURL, strInput));
m_streamWriter.Flush();
m_streamWriter.Close();
}
}
Well I had the same problem. And solved it now. It is kind of late suggestion but may be help for others.
Include the following using statements in the console examples below.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
Use of the FileStream Class
The examples below use the FileStream class, which has an option that causes asynchronous I/O to occur at the operating system level. In many cases, this will avoid blocking a ThreadPool thread. To enable this option, you must specify the useAsync=true or options=FileOptions.Asynchronous argument in the constructor call.
StreamReader and StreamWriter do not have this option if you open them directly by specifying a file path. StreamReader/Writer do have this option if you provide them a Stream that was opened by the FileStream class. Note that asynchrony provides a responsiveness advantage in UI apps even if a thread pool thread is blocked, since the UI thread is not blocked during the wait.
Writing Text
The following example writes text to a file. At each await statement, the method immediately exits. When the file I/O is complete, the method resumes at the statement following the await statement. Note that the async modifier is in the definition of methods that use the await statement.
static void Main(string[] args)
{
ProcessWrite().Wait();
Console.Write("Done ");
Console.ReadKey();
}
static Task ProcessWrite()
{
string filePath = #"c:\temp2\temp2.txt";
string text = "Hello World\r\n";
return WriteTextAsync(filePath, text);
}
static async Task WriteTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath,
FileMode.Append, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
};
}
Reading Text
The following example reads text from a file. The text is buffered and, in this case, placed into a StringBuilder. Unlike in the previous example, the evaluation of the await produces a value. The ReadAsync method returns a Task, so the evaluation of the await produces an Int32 value (numRead) that is returned after the operation completes..
static void Main(string[] args)
{
ProcessRead().Wait();
Console.Write("Done ");
Console.ReadKey();
}
static async Task ProcessRead()
{
string filePath = #"c:\temp2\temp2.txt";
if (File.Exists(filePath) == false)
{
Console.WriteLine("file not found: " + filePath);
}
else {
try {
string text = await ReadTextAsync(filePath);
Console.WriteLine(text);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
static 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();
}
}
Original source was here but unfortunately the link seems dead now.
New source can be found here.
Hope that helps...
Example of a helper method to handle async writing to a file.
public async Task FileWriteAsync(string filePath, string messaage, bool append = true)
{
using (FileStream stream = new FileStream(filePath, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
using (StreamWriter sw = new StreamWriter(stream))
{
await sw.WriteLineAsync(messaage);
}
}
Writing asynchronously to the file will not solve this issue. You'll need to wait for the file to be available.
If you use a simple StreamWriter, you could replace it with a simple class. No need for async/await. This is an example of writing a text file.
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;
class LogWriter : IDisposable
{
private BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
private StreamWriter log = null;
bool run = true;
Task task = null;
public LogWriter(string logFilePath)
{
log = new StreamWriter(logFilePath);
task = Task.Run(() =>
{
while (run)
{
log.WriteLine(blockingCollection.Take());
}
});
}
public void WriteLine(string value)
{
blockingCollection.Add(value);
}
public void Dispose()
{
run = false;
task.Dispose();
log.Close();
log.Dispose();
}
}
To use it, do just like you would do with a StreamWriter:
using (var log = new LogWriter(logFileName))
{
log.WriteLine("Hello world");
// Code here that should not be blocked by writing to the file
}
Simple and straightforward solution:
using var file = new StreamWriter(path);
await file.WriteAsync(content);
The accepted answer has the common async pitfall - the buffers are not flushed async-ly. Check this out: https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#always-call-flushasync-on-streamwriters-or-streams-before-calling-dispose
Either use the new await using or flush the buffer manually before disposing
await using (var file = new StreamWriter(path)) //mind the "await using"
{
await file.WriteAsync(content);
}
or
using (var streamWriter = new StreamWriter(context.Response.Body))
{
await streamWriter.WriteAsync("Hello World");
await streamWriter.FlushAsync();
}
Ultimately it depends why you're trying to do it.
If you aren't going to be writing too much data to the file, you can constantly open and close it.
Alternatively, if you know when you want the file open and when you want it closed, you can open it when it's needed, then keep it open for writing until the point you know it's no longer needed.

Why StreamWriter can't get string in it's constructor? [duplicate]

I'm having trouble when creating a StreamWriter object in windows-8, usually I just create an instance just passing a string as a parameter, but in Windows 8 I get an error that indicates that it should recieve a Stream, but I noticed that Stream is an abstract class, Does anybody knows how will be the code to write an xml file?, BTW I'm using .xml because I want to save the serialized object, or does anyone knows how to save to a file a serialized object in Windows 8?.
Any ideas?
Currently using Windows 8 Consumer Preview
Code:
StreamWriter sw = new StreamWriter("person.xml");
Error:
The best overloaded method match for 'System.IO.StreamWriter.StreamWriter(System.IO.Stream)' has some invalid arguments
Instead of StreamWriter you would use something like this:
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync();
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
//TODO: Replace "Bytes" with the type you want to write.
dataWriter.WriteBytes(bytes);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
You can look at the StringIOExtensions class in the WinRTXamlToolkit library for sample use.
EDIT*
While all the above should work - they were written before the FileIO class became available in WinRT, which simplifies most of the common scenarios that the above solution solves since you can now just call await FileIO.WriteTextAsync(file, contents) to write text into file and there are also similar methods to read, write or append strings, bytes, lists of strings or IBuffers.
You can create a common static method which you can use through out application like this
private async Task<T> ReadXml<T>(StorageFile xmldata)
{
XmlSerializer xmlser = new XmlSerializer(typeof(List<myclass>));
T data;
using (var strm = await xmldata.OpenStreamForReadAsync())
{
TextReader Reader = new StreamReader(strm);
data = (T)xmlser.Deserialize(Reader);
}
return data;
}
private async Task writeXml<T>(T Data, StorageFile file)
{
try
{
StringWriter sw = new StringWriter();
XmlSerializer xmlser = new XmlSerializer(typeof(T));
xmlser.Serialize(sw, Data);
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteString(sw.ToString());
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
}
catch (Exception e)
{
throw new NotImplementedException(e.Message.ToString());
}
}
to write xml simply use
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("data.xml",CreationCollisionOption.ReplaceExisting);
await writeXml(Data,file);
and to read xml use
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("data.xml");
Data = await ReadXml<List<myclass>>(file);

Categories

Resources