Stream was not readable with Using - c#

I am getting an error
File is being used by another process
trying to implement using for a FileStream. However, I encountered the error of Stream was not readable.
This is my code:
Before: working, but encounters 'file being used by another process' error periodically
EmailMessage responseMessageWithAttachment = responseMessage.Save();
foreach (var attachment in email.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load();
fileAttachment.Load(AppConfig.EmailSaveFilePath + fileAttachment.Name);
FileStream fs = new FileStream(AppConfig.EmailSaveFilePath + fileAttachment.Name, FileMode.OpenOrCreate);
responseMessageWithAttachment.Attachments.AddFileAttachment(attachment.Name, fs);
}
}
responseMessageWithAttachment.SendAndSaveCopy();
After: encounters 'stream was not readable' error
EmailMessage responseMessageWithAttachment = responseMessage.Save();
foreach (var attachment in email.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load();
fileAttachment.Load(AppConfig.EmailSaveFilePath + fileAttachment.Name);
using (FileStream fs = new FileStream(AppConfig.EmailSaveFilePath + fileAttachment.Name, FileMode.OpenOrCreate))
{
responseMessageWithAttachment.Attachments.AddFileAttachment(attachment.Name, fs);
};
}
}
responseMessageWithAttachment.SendAndSaveCopy();

working, but encounter 'file being used by another process' error periodically
This means what it says: some other process is touching the file. If you want to solve this, you need to figure out what's using the file. This will happen whether you use using or not.
If this code is running multiple times in parallel, it could be your own code interfering. Either way, you could avoid it by open for reading only, but specifically allowing other processes to open it for writing. You would do that like this:
var fs = new FileStream(Path.Combine(AppConfig.EmailSaveFilePath, fileAttachment.Name),
FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
encounter 'stream was not readable' error
This depends on how AddFileAttachment is implemented. You don't show the stack trace, so it's possible that it doesn't read the stream until you call SendAndSaveCopy(), which is outside the using and the stream is closed.
An easy way to work around this is to just use the overload of AddFileAttachment that just takes the path to the file as a string, so you don't need to manage the FileStream yourself:
responseMessageWithAttachment.Attachments.AddFileAttachment(attachment.Name,
Path.Combine(AppConfig.EmailSaveFilePath, fileAttachment.Name));
I use Path.Combine since it avoids problems where there may or may not be a trailing \ in your EmailSaveFilePath setting.

I wonder if you can avoid saving the files and just use Content and AddFileAttachment(String, Byte[])
foreach (var attachment in email.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load();
responseMessageWithAttachment.Attachments.AddFileAttachment(attachment.Name, fileAttachment.Content);
}
}
responseMessageWithAttachment.SendAndSaveCopy();

Related

Is possible to create zip password protected file without first creating file, then zip it

I am writing data into text file and using below code,
await using var file = new StreamWriter(filePath);
foreach (var packet in resultPackets)
{
file.WriteLine(JsonConvert.SerializeObject(packet));
}
And I am using below code to zip the file with password protected using `DotNetZip,
using (ZipFile zip = new ZipFile())
{
zip.Password = "password";
zip.AddFile(filePath);
zip.Save(#"C:\tmp\data4.zip");
}
Is there a way to combined both, I want to create a file on the fly as password protected.
I don't
want to create first file with data, t
then create zip file from it
and delete the base file
Is this possible? Thanks!
Okay, so since this is still unanswered, here's a small program that does the job for me:
using (var stream = new MemoryStream())
using (var streamWriter = new StreamWriter(stream))
{
// Insert your code in here, i.e.
//foreach (var packet in resultPackets)
//{
// streamWriter.WriteLine(JsonConvert.SerializeObject(packet));
//}
// ... instead I write a simple string.
streamWriter.Write("Hello World!");
// Make sure the contents from the StreamWriter are actually flushed into the stream, then seek the beginning of the stream.
streamWriter.Flush();
stream.Seek(0, SeekOrigin.Begin);
using (ZipFile zip = new ZipFile())
{
zip.Password = "password";
// Write the contents of the stream into a file that is called "test.txt"
zip.AddEntry("test.txt", stream);
// Save the archive.
zip.Save("test.zip");
}
}
Note how AddEntry does not create any form of temporary file. Instead, when the archive is saved, the contents of the stream are read and put into a compressed file within the archive. However, be aware that the whole content of the file are completely kept in memory before it the archive is written to the disk.

Deleting files gives an error (The process cannot access the file..)

I'm currently debugging my code because it gives me an error:
The process cannot access the file because it is being used by another process.
And i think that the error occurs in this lines of code
foreach (var filename in filenames)
{
var file = Path.Combine(filePath, filename);
mail.Attachments.Add(new Attachment(file));
}
// Send Mail
smtpServer.Send(mail);
DeleteFiles();
I want to delete the files in the folder when the mail is sent using this method
private void DeleteFiles()
{
string filePath = Server.MapPath("~/Content/attachments");
Array.ForEach(Directory.GetFiles(filePath), System.IO.File.Delete);
}
I read about closing/disposing? FileStream and etc. but how can i use that in my code? Thanks in advance.
mail.dispose(); You should dispose mail before deleting the file. This should remove the lock on the file.
foreach (var filename in filenames)
{
var file = Path.Combine(filePath, filename);
mail.Attachments.Add(new Attachment(file));
}
// Send Mail
smtpServer.Send(mail);
mail.Dispose();
DeleteFiles();
https://msdn.microsoft.com/en-us/library/0w54a951(v=vs.110).aspx
using(FileStream stream = new FileStream("thepath"))
{
//do stuff with the file
stream .Close();
}
Now the stream will be closed and disposed.

"The process cannot access the file because it is being used by another process" with Images

I've seen many issues like this that have been solved and the problem was mostly due to streams not being disposed of properly.
My issue is slightly different, here follow a code snippet
foreach (Images item in ListOfImages)
{
newPath = Path.Combine(newPath, item.ImageName + item.ImageExtension);
File.Create(newPath);
File.WriteAllBytes(newPath, item.File);
}
Where Images is a custom struct and item.File is the raw data, byte[].
My issue is that at the line where the WriteAllBytes is called, an exception is thrown. The message reads:
The process cannot access the file because it is being used by another process
Again I have no clue how am I going to somehow close the process.
Since File.Create returns the stream i would dispose it properly:
using(var stream = File.Create(newPath)){}
File.WriteAllBytes(newPath, item.File);
or you can use the stream to write to the file directly:
using (FileStream fs = File.Create(newPath))
{
fs.Write(item.File, 0, item.File.Length);
}
or, probably the easiest, use File.WriteAllBytes alone:
File.WriteAllBytes(newPath, item.File);
Creates a new file, writes the specified byte array to the file, and
then closes the file. If the target file already exists, it is
overwritten.
You state that your problem has nothing to do with disposing streams but check this MSDN article:
http://msdn.microsoft.com/en-us/library/d62kzs03.aspx
What does File.Create return? A FileStream!!!!
And, at the end of the day, why are you using File.Create if File.WriteAllBytes creates a file if this doesn't exist? ;)
Creates a new file, writes the specified byte array to the file, and
then closes the file. If the target file already exists, it is
overwritten.
Check it on MSDN too: http://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes.aspx
using (FileStream fs =
new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
Your log may be write locked, so try with FileShare.ReadWrite.
The create method opens the file for writing and returns a FileStream object for you to work with. Just because you are not referencing it does not mean it does not need to be returned.
foreach (Images item in ListOfImages)
{
newPath = Path.Combine(newPath, item.ImageName + item.ImageExtension);
FileStream f = File.Create(newPath);
f.Write(item.File, 0, item.File.Length);
}
The File.WriteAllBytes creates the file if necessary. You can juts use:
foreach (Images item in ListOfImages)
{
newPath = Path.Combine(newPath, item.ImageName + item.ImageExtension);
File.WriteAllBytes(newPath, item.File);
}
And are you combine path correctly?
This is the most specific way to accomplish what you are trying to do:
foreach (Images item in ListOfImages)
{
using (System.IO.FileStream output = new System.IO.FileStream(Path.Combine(newPath, item.ImageName + item.ImageExtension),
System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
output.Write(item.File, 0, item.File.Length);
output.Flush();
output.Close();
}
}
You also need to fix your logic for creating the path, which I have done in my example above. You were concatenating the newPath over and over again.
Force the garbage collector to clean.
GC.Collect();

Operation not permitted on IsolatedStorageFileStream error

It gives operation not permitted on IsolatedStorageFileStream error when I try to save the content of the file in the fileStream fs.
var appStorage = IsolatedStorageFile.GetUserStoreForApplication();
string[] fileList = appStorage.GetFileNames();
foreach (string fileName in fileList)
{
using (var file = appStorage.OpenFile(fileName, FileMode.Open))
{
if (fileName != "__ApplicationSettings")
{
var fs = new IsolatedStorageFileStream(fileName, FileMode.Open, FileAccess.Read, appStorage);
string abc = fs.ToString();
meTextBlock.Text = abc;
//MemoryStream ms = appStorage.OpenFile(fileName, FileMode.Open, FileAccess.Read);
clientUpload.UploadAsync(SkyDriveFolderId, fileName, fs);
}
}
}
Why did you add the inner using (var file = appStorage.OpenFile(fileName, FileMode.Open))?
Seems to me the problem is that you're opening a stream to read the file and then opening another, without closing the previous one!
If you remove that line (seems not to be doing anything there) it should work fine.
Oh, and the fs.ToString() will only get you the Type name, not the file content; to read the file, use a StreamReader with the fs.
This error consistently occurs when an isolated storage file is opened by one stream (or reader or else) and, is being accessed by another object while the first stream (or reader, or else) have not yet relinquished the file. Go through your code carefully in all places where you access isolated storage files and make sure you close each file before something else is accessing it. Pedro Lamas is correct for this particular case, I just wanted to provide some general feedback. If you search google for "Operation not permitted on IsolatedStorageFileStream error" questions and answers, you will see the trend. The error message could be more descriptive though.
Try this approach
using (var isf = IsolatedStorageFile.GetUserStoreForApplication())
{
if (IsolatedStorageFile.IsEnabled)
{
if (isf.FileExists(localFileName))
{
using (var isfs = new IsolatedStorageFileStream(localFileName, FileMode.Open, isf))
{
using (var sr = new StreamReader(isfs))
{
var data = sr.ReadToEnd();
if (data != null)
{
...

Converting attachment to image

Up to know i can load the attachments to memory and i know its right cause i can print the name of the file. What i need is to convert this attachment to an image object which i will later add to a sharepoint picture library. But forget about the sharepoint part i know how to do that, am stuck in the part that after loading the attachments how do i conver this into images. I dont want to save the images in disk cause thats not the point i already load them in memory.
foreach (Item item in findResults.Items)
{
if (item is EmailMessage && item.HasAttachments)
{
EmailMessage message = EmailMessage.Bind(service, item.Id, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments));
foreach (Attachment attachment in message.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
// Load the file attachment into memory and print out its file name.
fileAttachment.Load();
Console.WriteLine("Attachment name: " + fileAttachment.Name);
//this is where i would create the image of object but dont know how
}
}
}
}
You already have the FileAttachment object, and you even access one of its properties. You only need to take the next step, and access not only the Name but also the Content.
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load();
byte[] fileContent = fileAttachment.Content;
}
This will give you the contents on the attachemnts, as an array of bytes. I don't remember what the Sharepoint API wants to receive, but it's either this byte array or something you can easily build out of it.

Categories