Multiple using declarations throw 'IOException' but statements don't when writing files - c#

using declarations were just introduced in C# 8.0 but they don't behave the same as using blocks, or so i think.
The following nested using block works fine:
using (var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey))
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
resource?.CopyTo(file);
}
But when i convert to a using declaration as follows, i get an IOException which says the file is being used by another process:
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using var file = new FileStream(path, FileMode.Create, FileAccess.Write);
resource?.CopyTo(file);
I want to understand what's different and how\when to use the new using declaration?

Both using declaration differ in the way they resolve scope.
Old Using used to define its own scope using the curly braces,
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
resource?.CopyTo(file);
}
Here both resource and file will be disposed the moment the closing braces are found.
With, The new declaration if you haven,t defined a scope like the above, It will automatically attach to the nearest scope,
void certainMethod()
{
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using var file = new FileStream(path, FileMode.Create, FileAccess.Write);
resource?.CopyTo(file);
}
Here when the method call to certainMethod ends, Dispose for resource and file will be called.
Edit: To your case,
There shouln't be any issue if your code is doing just this, But if there are two of such blocks, First one will work but second will fail,
Example,
void certainMethod()
{
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using var file = new FileStream(path, FileMode.Create, FileAccess.Write);
resource?.CopyTo(file);
using var oneMoreFile = new FileStream(path, FileMode.Create, FileAccess.Write);
//This will fail
resource?.CopyTo(oneMoreFile );
}

Related

C# using Statement when working with Stream's objects

I have the method :
public static void Main()
{
string path = #"C:\Temp\ProgrammingInCSharp\DirectoryInfo\111.txt";
using (FileStream fileStream = File.Create(path))
{
using (BufferedStream bufferedStream = new BufferedStream(fileStream))
{
using (StreamWriter streamWriter = new StreamWriter(bufferedStream))
{
streamWriter.WriteLine("A line of text.");
}
}
}
}
Which is using 3 using statements and method works perfectly : create 111.txt and write "A line of text." inside it.
But when I change the method to :
public static void Main()
{
string path = #"C:\Temp\ProgrammingInCSharp\DirectoryInfo\111.txt";
FileStream fileStream = File.Create(path);
BufferedStream bufferedStream = new BufferedStream(fileStream);
StreamWriter streamWriter = new StreamWriter(bufferedStream);
streamWriter.WriteLine("A line of text.");
}
It just creates 111.txt file but doesn't write "A line of text." inside.
I cannot understand why.
As I read using Statement just call Dispose() method when the object leaves the scope of using Statement. So it should be used to dispose unmanaged code from CLR but why without using Statement I cannot write the text message to my machine's file?
There is caching going on in the background: WriteLine writes to a cache, not directly to the file. So if the file isn't closed properly, the cache doesn't actually get written to the disk. The using statement disposes the object, which flushes the cache into the file and closes the file.
You can see the source code for StreamWriter.Dispose() here (notice that it calls Flush()): https://referencesource.microsoft.com/#mscorlib/system/io/streamwriter.cs,236
Note that with multiple using statements, you only need one code block. The effect is the same, but it's just easier to read.
using (FileStream fileStream = File.Create(path))
using (BufferedStream bufferedStream = new BufferedStream(fileStream))
using (StreamWriter streamWriter = new StreamWriter(bufferedStream))
{
streamWriter.WriteLine("A line of text.");
}

Issues with File Copy Asynchronously

I am copying files asynchronously with the article Microsoft provided https://learn.microsoft.com/en-us/dotnet/standard/io/asynchronous-file-i-o
The issue I am running into using this is that when the files are finished copying, it doesn't keep the date modified value and is set to the time the file was created.
To compensate for that, I am trying to set the date modified time for each file after their finished copying with the File.SetLastWriteTime static method.
foreach (var file in dir.EnumerateFiles())
{
string temppath = Path.Combine(destDirName, file.Name);
using (FileStream reader = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
{
using (FileStream writer = new FileStream(temppath, FileMode.Create, FileAccess.ReadWrite))
{
await reader.CopyToAsync(writer);
File.SetLastWriteTime(temppath, file.LastWriteTime);
}
}
}
Unfortunately, it seems that the File.SetLastWriteTime method executes immediately before await reader.CopyToAsync(writer) has finished.
How can I make sure that the File.SetLastWriteTime method isn't executed until after reader.CopyToAsync has finished?
It appears to work as intended if I change the method to copy synchronously within a Task.Run, but not sure if that is the correct way to do it.
I was able to figure it out.
The reason why it couldn't set the file time is because it was still within the stream.
I simply moved the method outside of the write stream and that resolved the problem.
foreach (var file in dir.EnumerateFiles())
{
string temppath = Path.Combine(destDirName, file.Name);
using (FileStream reader = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
{
using (FileStream writer = new FileStream(temppath, FileMode.Create, FileAccess.ReadWrite))
{
await reader.CopyToAsync(writer);
}
File.SetLastWriteTime(temppath, file.LastWriteTime);
}
}

How to save attachments?

I am using MailKit/MimeKit 1.2.7 (latest NuGet version).
I have been reading the API documentation and several posts on stackoverflow. But I still wasn't able to successfully save email attachments as a file.
Here is my current code:
var mimePart = (attachment as MimePart);
var memoryStream = new MemoryStream();
mimePart.ContentObject.DecodeTo(attachmentStream);
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
memoryStream.CopyTo(fileStream);
}
I have been trying this code with different kinds of attachments. The created file on my disc is always empty.
What am I missing?
The problem with the above code is that you are forgetting to reset the memoryStream.Position back to 0 :-)
However, a better way of doing what you want to do is this:
var mimePart = (attachment as MimePart);
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
mimePart.ContentObject.DecodeTo(fileStream);
}
In other words, there's no need to use a temporary memory stream.

System.IO.Abstraction can't find IStreamWriter

I am trying to unit test a method that calls StreamWriter. I am trying to use System.IO.Abstraction in order to mock StreamWriter however I can't find the interface on the last NuGet looked into the source code as well but have no idea what is the replacement for this, other stuff like FileInfo is working as expected.
Thanks,
Taking #BarryMcDermid's answer and altering it slightly you can do something along the lines of:
using (Stream fs = _fileSystem.FileStream.Create(filePath, FileMode.Create))
{
ms.CopyTo(fs);
fs.Flush();
fs.Close();
}
By declaring the 'FileStream' as a Stream instead of a FileStream you'll then be able to use System.IO.Abstraction.TestingHelpers to test this code without getting exceptions.
There's a more fully worked example of that in my question here.
I was also looking for how to mock a FileStream via System.IO.Abstractions and couldn't see it initially. It's Hanging off the FileInfo Object. It results in slightly clunky code and required a cast. My Original Code:
FileStream fileStreamBack = null;
using (fileStreamBack = new FileStream(fileFrom, FileMode.Open, FileAccess.Read))
using (var fileStreamf = new FileStream(fileTo, FileMode.Create, FileAccess.Write))
{
fileStreamBack.CopyTo(fileStreamf); // Use the .Net
fileStreamBack.Flush(); // Making sure
fileStreamBack.Close(); // Making sure
}
Now Replaced with
FileStream fileStreamBack = null;
using (fileStreamBack = (FileStream)_fileSystem.FileInfo.FromFileName(fileFrom).Open(FileMode.Open, FileAccess.Read))
using (var fileStreamf = (FileStream)_fileSystem.FileInfo.FromFileName(fileTo).Open(FileMode.Create, FileAccess.Write))
{
fileStreamBack.CopyTo(fileStreamf); // Use the .Net
fileStreamBack.Flush(); // Making sure
fileStreamBack.Close(); // Making sure
}
There is also a MockFileStream object in the System.IO.Abstractions.TestingHelpers (for our convenience!)

File is already in use FileAccess C#

public void WriteListToFile(Lists lists, string filePath)
{
FileStream outFile;
BinaryFormatter bFormatter = new BinaryFormatter();
// Ppen file for output
outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);
// Output object to file via serialization
bFormatter.Serialize(outFile, lists);
// Close file
outFile.Close();
}
Whenever I try to output data to a .dat file I get an error saying that the file is already in use. How do I fix this?
EDT: Turns out it wouldn't let me save to an empty file so I create a new void to input data and then it allowed me to save over the file.
The immediate answer is "release the lock that some process has on the file".
Something already has the file open. You need to look at code and other processes that may access that file to find the root cause.
I note that you're not making use of using statements. If an exception were thrown in the block of code you show, outputFile.Close() would never execute, leaving the file open.
Try rewriting your code (and any similar code) like
public void WriteListToFile(Lists lists, string filePath)
{
BinaryFormatter bFormatter = new BinaryFormatter();
// Ppen file for output
using (FileStream outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
// Output object to file via serialization
bFormatter.Serialize(outFile, lists);
// Close file
outFile.Close();
}
}
The using keyword is a syntactic shortcut for
var outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);
try
{
// Do stuff with outFile
}
finally
{
outFile.Dispose();
}
and ensures that outFile is disposed (which also closes it) whether or not an exception is thrown.
you can try this:
outFile.Dispose();

Categories

Resources