This question already has answers here:
Sharing violation IOException while reading and writing to file C#
(4 answers)
Closed 9 years ago.
I'm using this code for saving logs in may C# monotouch application:
public static void writeExeption(string message){
string path= StorageClass .LogsPath ;
string filepath= Path.Combine (path ,"Log.txt");
if(!File.Exists (filepath )){
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine ("--------------------------------------------------------------------------" +
"--------------------");
sw.WriteLine("blahblah...");
sw.WriteLine ("--------------------------------------------------------------------------" +
"--------------------");
}
}
using (StreamWriter w = File.AppendText(filepath ))
{
Log(message , w);
}
}
public static void Log(string logMessage, TextWriter w)
{
w.Write("\r\nLog Entry : ");
w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", logMessage);
w.WriteLine ("--------------------------------------------------------------------------" +
"--------------------");
}
But in the application I get this error:
Sharing violation on path 'File Path'
Try adding to enclose the StreamWriter which appends the data in a lock statement.
First, add an object to refer to:
static object _locker = new object();
Then, modify the writeExeption method by locking the last using statement:
lock (_locker)
{
using (StreamWriter w = File.AppendText(filepath))
{
Log(message, w);
}
}
If this still doesn't work, it means that some other application is using your file. If it works, it means that you are logging on multiple threads.
Seems like you're accessing one file in two or more places (could be in different threads).
Use these methods to read/write files in multi-thread apps to avoid such error:
/// <summary>
/// Writes the file exclusively. No one could do anything with file while it writing
/// </summary>
/// <param name="path">Path.</param>
/// <param name="data">Data.</param>
public static void WaitFileAndWrite(string path, byte[] data)
{
while (true) {
Stream fileStream = null;
try {
// FileShare.None is important: exclusive access during writing
fileStream = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
fileStream.Write(data, 0, data.Length);
break;
} catch (IOException ex) {
Console.WriteLine (ex);
Thread.Sleep(10);
} finally {
if (fileStream != null) {
fileStream.Close();
}
}
}
}
/// <summary>
/// Waits the file and read.
/// </summary>
/// <returns>The file and read.</returns>
/// <param name="fileName">File name.</param>
public static byte [] WaitFileAndRead(string fileName)
{
byte[] result = null;
if (File.Exists(fileName)) {
while (true) {
Stream fileStream = null;
try {
fileStream = File.OpenRead(fileName);
var length = fileStream.Length;
result = new byte[length];
fileStream.Read(result, 0, Convert.ToInt32(length));
break;
} catch (IOException ex) {
Console.WriteLine (ex);
Thread.Sleep(10);
} finally {
if (fileStream != null) {
fileStream.Close();
}
}
}
}
return result;
}
}
Yet you should be accurate. If someone open file for read/write operations and don't close it, these method will try to open infinitely.
Related
i am struggling with getting SHA256 sum of a file.
When program starts method GetSHA256FromStream is called.
The error occurs in method GetSHA256 when File.Open is called.
I am running Visual Studio as Administrator.
ERROR:
System.IO.IOException: 'The process cannot access the file 'C:\Users\WS1\AppData\Local\Temp\test.ttttt' because it is being
used by another process.'
I don't really know if i need to use async/await for working with files.
public static string GetSHA256FromStream(Stream s)
{
string _tpath = Helper.GetTEMPPath("test.ttttt"); // %TEMP%\\test.ttttt
Helper.WriteStreamToFile(s, _tpath);
return Checksum.GetSHA256(_tpath, true);
}
public async static void WriteStreamToFile(Stream s, string outpath)
{
try
{
FileStream fStream = File.Open(outpath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
s.Seek(0, SeekOrigin.Begin);
await s.CopyToAsync(fStream);
fStream.Close();
}
catch (Exception e)
{
return;
}
}
public static string GetSHA256(string text, bool isFile = false)
{
SHA256 sha256 = SHA256.Create();
byte[] hash;
if (isFile)
{
FileStream stream = File.OpenRead(text);
hash = sha256.ComputeHash(stream);
}
else
{
byte[] textBytes = Encoding.Default.GetBytes(text);
hash = sha256.ComputeHash(textBytes);
}
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
The method WriteStreamToFile is async, but you are not awaiting it in GetSHA256FromStream. Thus, you are already calling GetSHA256() and trying to open the file, while WriteStreamToFile is still writing.
You could for instance make GetSHA256FromStream also async and then await writing to the file and then once that task is finished calculate the checksum
BTW, you should not return void on async methods but a Task
public static async Task<string> GetSHA256FromStream(Stream s)
{
try {
string _tpath = Helper.GetTEMPPath("test.ttttt"); // %TEMP%\\test.ttttt
await Helper.WriteStreamToFile(s, _tpath);
return Checksum.GetSHA256(_tpath, true);
}
catch (Exception e) {
//some error logging
}
}
public async static Task WriteStreamToFile(Stream s, string outpath)
{
try
{
FileStream fStream = File.Open(outpath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
s.Seek(0, SeekOrigin.Begin);
await s.CopyToAsync(fStream);
fStream.Close();
}
catch (Exception e)
{
//Don't use empty catches but log some error here
}
}
I am creating a program which takes passwords and applies an encoding on them onto a file which I have creatively labeled a PASSWORDFILE file. I am a self taught amateur programmer and this is my first time using streams => I'm sorry my code isn't cleaner. When I add a password to my file, the file refuses to open (giving me a "System.IO.IOException: The process cannot access the file '[file path here]' because it is being used by another process."). I have made sure I am closing all my streams yet this error still persists.
To add further confusion:
namespace PasswordSaver
{
[Serializable]
class Password
{
public string ID;
string baseWord;
public Password(string password, string ID)
{
this.ID = ID;
baseWord = password;
}
public virtual string GetPassword()
{
return baseWord;
}
}
[Serializable]
class EncodedPassword : Password
{
EncoderAndDecoder Encoder;
public EncodedPassword(string decodedBasePassword, string ID) : base(decodedBasePassword, ID)
{
Encoder = new EncoderAndDecoder();
}
public override string GetPassword()
{
return Encoder.Encode(base.GetPassword(), out _);
}
}
[Serializable]
class EncodedPasswordWithAddendum : EncodedPassword
{
string addendum;
public EncodedPasswordWithAddendum(string decodedBasePassword, string addendum, string ID) : base(decodedBasePassword, ID)
{
this.addendum = addendum;
}
public override string GetPassword()
{
return base.GetPassword() + addendum;
}
}
}
the error only occurs when I attempt to add an EncodedPassword or EncodedPasswordWithAddendum instances but not a Password instance.
My writing code is
namespace PasswordSaver
{
class PasswordWriter
{
public readonly string saveFilePath;
static string directory = Directory.GetCurrentDirectory();
#region Constructors
public PasswordWriter()
{
saveFilePath = directory + #"\PasswordSaver"
+ ".passwordfile";
}
public PasswordWriter(string saveFilePath)
{
this.saveFilePath = saveFilePath;
}
#endregion
#region Individual Writing Functions
private void WriteBinary(object objectToEncode)
{
WriteBinary(objectToEncode, out _);
}
private void WriteBinary(object objectToEncode, out Exception exception)
{
exception = null;
try
{
IFormatter binaryFormatter = new BinaryFormatter();
Stream fileStream = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
Stream memoryStream = new MemoryStream();
memoryStream.Position = memoryStream.Length;
binaryFormatter.Serialize(memoryStream, objectToEncode);
EncodeFromStream(ref memoryStream, ref fileStream);
fileStream.Close();
memoryStream.Close();
}
catch (Exception e)
{
exception = e;
}
}
#endregion
#region File Read and Writing
public void WriteFile(Password[] passwords)
{
if (File.Exists(saveFilePath))
{
Stream stream = new FileStream(saveFilePath, FileMode.Truncate, FileAccess.Write);
stream.Close();
}
WriteBinary(passwords.Length);
foreach (Password password in passwords)
{
WriteBinary(password);
}
}
public void WriteToFile(Password password)
{
Password[] oldPasswords = ReadFile();
Password[] passwords = new Password[oldPasswords.Length + 1];
for (int i = 0; i < oldPasswords.Length; i++)
{
passwords[i] = oldPasswords[i];
}
passwords[oldPasswords.Length] = password;
WriteFile(passwords);
}
public bool ReplacePassword(string oldPasswordID, Password newPassword)
{
Password[] passwords = ReadFile();
for (int i = 0; i < passwords.Length; i++)
{
if (passwords[i].ID == oldPasswordID)
{
passwords[i] = newPassword;
return true;
}
}
return false;
}
public Password[] ReadFile()
{
Stream fileStream = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.Read);
IFormatter binaryFormatter = new BinaryFormatter();
Stream memoryStream = new MemoryStream();
DecodeFromStream(ref fileStream, ref memoryStream);
fileStream.Close();
memoryStream.Position = 0;
int length = (int) binaryFormatter.Deserialize(memoryStream);
//Console.WriteLine(length + " is the length");//debug
Password[] passwords = new Password[length];
for (int i = 0; i < length; i++)
{
//Console.WriteLine(memoryStream.Position + " " + memoryStream.Length);//debug
//Console.WriteLine(i);//debug
passwords[i] = (Password)binaryFormatter.Deserialize(memoryStream);
}
memoryStream.Close();
return passwords;
}
#endregion
#region Encode and Decode
private void EncodeFromStream(ref Stream stream, ref Stream newStream)
{
stream.Position = 0;
newStream.Position = newStream.Length;
for (int i = 0; i < stream.Length; i++)
{
int integer = stream.ReadByte();
byte originalByte = (byte)integer;// get a byte off of the line
//Encode byte here
newStream.WriteByte(setOfBits1);
newStream.WriteByte(setOfBits2);
}
}
private void DecodeFromStream(ref Stream stream, ref Stream newStream)
{
newStream.Position = newStream.Length;
stream.Position = 0;
for (int i = 0; i < (stream.Length / 2); i++)// stream.Length / 2 because the program reads two bytes per iteration of the for loop
{
//I decode the bytes here
newStream.WriteByte(originalByte);
}
}
#endregion
public void WriteContentsToFile()
{
Stream stream = new FileStream(saveFilePath + "1", FileMode.OpenOrCreate, FileAccess.ReadWrite);
Stream stream1 = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
this.DecodeFromStream(ref stream1, ref stream);
stream.Close();
stream1.Close();
}
}
}
I have removed the code that encoded and decoded the streams in EncodeFromStream and DecodeFromStream.
any occurrence of new FileStream(saveFilePath + "1", FileMode.OpenOrCreate, FileAccess.ReadWrite) is a where I was writing to a seperate file in a decoded format. To distinguish the two files I changed the file type from PASSWORDFILE to PASSWORDFILE1.
In Conclusion:
I am using the WriteFile or WriteToFile methods with a Password[] that contains an EncodedPassword or EncodedPasswordWithAddendum. then when I try to open the file through a FileStream (usually through the method ReadFile) I get the Exception "System.IO.IOException: The process cannot access the file '[file path here]' because it is being used by another process".
Thank you for your help.
Streams usually contain unamanged resources (the OS Filehandles), so they implement IDisposeable.
While you can always be certain that the GC will clean up disposeable stuff eventually (latest at application closing), usually that is way to late. You have to do it explicitly. And for that I have a one rule regarding IDisposeable stuff:
"Never split up the creation and disposing of a disposeable resource. Create. Use. Dispose. All in the same piece of code, ideally using a using block."
The only exception I ever encountered a logfiles. Nothing else is remotely worth the trouble and headaches of keeping something disposeable open. Especially not performance.
As the using block uses a try...finally, you can be certain it will run. Compiler and runtime make certain finally blocks always run, even on function return, jump via goto or Exception cases.
In my class "DiaryManager" I got two List with two different types (T) and I want to save it to file, then I want to load it.
I got it to work with one of my list's as I am going to show you.
My list that I save and load in my working code is named "m_diary". The save method is this one:
/// <summary>
/// Saves the object information
/// </summary>
public void Save()
{
// Gain code access to the file that we are going
// to write to
try
{
// Create a FileStream that will write data to file.
FileStream writerFileStream =
new FileStream(DATA_FILENAME, FileMode.Create, FileAccess.Write);
// Save our dictionary of friends to file
m_formatter.Serialize(writerFileStream, m_diary);
// Close the writerFileStream when we are done.
writerFileStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
And my load method is this one:
/// <summary>
/// Load the object to the program
/// </summary>
public void Load()
{
// Check if we had previously Save information of our friends
// previously
if (File.Exists(DATA_FILENAME))
{
try
{
// Create a FileStream will gain read access to the
// data file.
FileStream readerFileStream = new FileStream(DATA_FILENAME,
FileMode.Open, FileAccess.Read);
// Reconstruct information of our friends from file.
m_diary = (List<Diary>)
m_formatter.Deserialize(readerFileStream);
// Close the readerFileStream when we are done
readerFileStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
The "DATA_FILENAME" is this constant:
private const string DATA_FILENAME = "TrainingDiary.dat";
This code works perfect from my windows form class.
But now Iv added one more list with a different type.
How do I save and load that second list to?? :)
Best regards
Cyrix
You can do it using similar code for the second list, or you can write a generic method:
public static void Save<T>(string fileName, List<T> list)
{
// Gain code access to the file that we are going
// to write to
try
{
// Create a FileStream that will write data to file.
using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, list);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
And a load method:
public static List<T> Load<T>(string fileName)
{
var list = new List<T>();
// Check if we had previously Save information of our friends
// previously
if (File.Exists(fileName))
{
try
{
// Create a FileStream will gain read access to the
// data file.
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
var formatter = new BinaryFormatter();
list = (List<T>)
formatter.Deserialize(stream);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return list;
}
Usage of Load:
var list = new List<string> {"one", "two", "three"};
Save("first.dat", list);
var list2 = Load<string>("first.dat");
foreach (var VARIABLE in list2)
{
Console.WriteLine(VARIABLE);
}
Also see using Statement to handle open/close streams;
You should create a class that contains all the data (lists) you want to save. Then just save that class to file.
I need to read csv file twice. but after first reading:
using (var csvReader = new StreamReader(file.InputStream))
{
fileFullText += csvReader.ReadToEnd();
file.InputStream.Seek(0, SeekOrigin.Begin);
csvReader.Close();
}
using file in enother function:
public static List<string> ParceCsv(HttpPostedFileBase file)
{
//file.InputStream.Seek(0, SeekOrigin.Begin);
using (var csvReader = new StreamReader(file.InputStream))
{
// csvReader.DiscardBufferedData();
// csvReader.BaseStream.Seek(0, SeekOrigin.Begin);
string inputLine = "";
var values = new List<string>();
while ((inputLine = csvReader.ReadLine()) != null)
{
values.Add(inputLine.Trim().Replace(",", "").Replace(" ", ""));
}
csvReader.Close();
return values;
}
}
The file.Length is 0.
Can anybody help?
The reason is that SteramReader's Dispose() method also closes the underlying stream; In your case file.InputStream. The using statement calls Dispose() implicitly. Try to replace using with disposes of both your StreamReaded-s after you finished both read operations. As I remember some stream classes have a bool option to leave underlying stream open after dispose.
.NET 4.5 fixed this issue by introducing leaveOpen parameter in SteamReader constructor. See: MSDN
public StreamReader(
Stream stream,
Encoding encoding,
bool detectEncodingFromByteOrderMarks,
int bufferSize,
bool leaveOpen
)
One more thing. You do not need to close SteramReader yourself (the line with csvReader.Close();) when you wrap it in using statement, thus Dispose() and Close() are the same in case of StreamReader.
if your using HttpPostedFileBase you need to clone it first,
use the code this git here
or just add this as a class in your namespace:
public static class HttpPostedFileBaseExtensions
{
public static Byte[] ToByteArray(this HttpPostedFileBase value)
{
if (value == null)
return null;
var array = new Byte[value.ContentLength];
value.InputStream.Position = 0;
value.InputStream.Read(array, 0, value.ContentLength);
return array;
}
}
now you can read the HttpPostedFileBase like so:
private static void doSomeStuff(HttpPostedFileBase file)
{
try
{
using (var reader = new MemoryStream(file.ToByteArray()))
{
// do some stuff... say read it to xml
using (var xmlTextReader = new XmlTextReader(reader))
{
}
}
}
catch (Exception ex)
{
throw ex;
}
}
after using this you can still write in your main code:
file.SaveAs(path);
and it will save it to the file.
I've noticed that if I persist an object back into file using a Datacontractserializer, if the length of the new xml is shorter than the xml originally present in the file the remnants of the original xml outwith the length of the new xml will remain in the file and will break the xml.
Does anyone have a good solution to fix this?
Here's the code I am using to persist the object:
/// <summary>
/// Flushes the current instance of the given type to the datastore.
/// </summary>
private void Flush()
{
try
{
string directory = Path.GetDirectoryName(this.fileName);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
FileStream stream = null;
try
{
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
for (int i = 0; i < 3; i++)
{
try
{
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, new System.Text.UTF8Encoding(false)))
{
stream = null;
// The serializer is initialized upstream.
this.serializer.WriteObject(writer, this.objectValue);
}
break;
}
catch (IOException)
{
Thread.Sleep(200);
}
}
}
finally
{
if (stream != null)
{
stream.Dispose();
}
}
}
catch
{
// TODO: Localize this
throw;
//throw new IOException(String.Format(CultureInfo.CurrentCulture, "Unable to save persistable object to file {0}", this.fileName));
}
}
It's because of how you are opening your stream with:
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
Try using:
stream = new FileStream(this.fileName, FileMode.Create);
See FileMode documentation.
I believe this is due to using FileMode.OpenOrCreate. If the file already exits, I think the file is being opened and parts of the data are being overwritten from the start byte. If you change to using FileMode.Create it forces any existing files to be overwritten.