This question already has answers here:
How to both read and write a file in C#
(6 answers)
Closed 5 years ago.
I need to read the content of a file and overwrite it while the file is locked. I don't want the file to be unlocked between read and write operations.
using (var file = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
using (var reader = new StreamReader(file, Encoding.Unicode))
using (var writer = new StreamWriter(file, Encoding.Unicode))
{
// read
// calculate new content
// overwrite - how do I do this???
}
}
If I use two FileStreams, the file is cleared when instantiating the writer but the file will be briefly unlocked between the reader and writer instantiation.
using (var reader = new StreamReader(new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None)))
{
// read
// calculate new content
}
using (var writer = new StreamWriter(new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)))
{
// write
}
If you keep open the original FileStream you can do it:
using (var file = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
// This overload will leave the underlying stream open
using (var reader = new StreamReader(file, Encoding.Unicode, true, 4096, true))
{
//Read
}
file.SetLength(0); //Truncate the file and seek to 0
using (var writer = new StreamWriter(file, Encoding.Unicode))
{
//Write the new data
}
}
Related
I want to read a binary file line by line (I'm writing of course continously, but I know that after 457 bytes new data start and I know exactly the byte structure and where which information is written to) and change a special entry of the line. I get an System.IO.IOException when I try to access the same file with both BinaryReader and BinaryWriter. I use locking to prevent that the file is accessed from somewhere else.
My code is:
using (FileStream fs2 = new FileStream(testfile, FileMode.Open, FileAccess.Read))
{
using (BinaryReader r = new BinaryReader(fs2))
{
using (BinaryWriter bw = new BinaryWriter(new FileStream(testfile, FileMode.Open, FileAccess.Write), utf8))
{
for (int i = 0; i < 11000; i+=457)
{
int myint = r.ReadInt64();
bw.Seek(i, SeekOrigin.Current);
bw.Write(myint*2);
}
}
}
}
How can I do this?
Do not create the second FileStream because the file is locked for the read operation by the first FileStream object.
If you are sure about file structure, the exception only can come out from 2nd FileStream instantiation. See link below for more information:
Read and Write to File at the same time
It is working for me using the following code:
if (File.Exists(testfile))
{
FileInfo fi = new FileInfo(testfile);
using (FileStream fs2 = new FileStream(testfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (BinaryReader r = new BinaryReader(fs2))
{
r.BaseStream.Seek(0, SeekOrigin.Begin);
using (BinaryWriter bw = new BinaryWriter(new FileStream(testfile, FileMode.Open, FileAccess.Write, FileShare.ReadWrite)))
{
for (int i = 0; i <= (fi.Length-177); i += 177)//181
{
}
}
}
}
}
I'm opening, unziping and reading file from remote share with followed code:
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 2 << 18))
using (ZipArchive za = new ZipArchive(fs))
{
foreach (ZipArchiveEntry zae in za.Entries)
using (StreamReader sr = new StreamReader(zae.Open(), Encoding.GetEncoding(1251), true, 2 << 18))
{
while (!sr.EndOfStream)
{
// reading logic
}
}
}
How to check if downloaded archive is corrupted?
Solution:
bool ValidateZip(FileStream fs)
{
using (BinaryReader br = new BinaryReader(fs))
{
br.BaseStream.Seek(-22, SeekOrigin.End);
return br.ReadUInt32() == 0x06054b50;
}
}
/*Initialize FileStreams for both writing and reading*/
writeStream = new FileStream(logfilePath, FileMode.Append, FileAccess.Write, FileShare.Read);
readStream = new FileStream(logfilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
/*Initialize the Writer and Reader*/
fileWrite = new StreamWriter(writeStream);
fileRead = new StreamReader(readStream);
So this is what I use to be able to constantly write and read to the same file. How can I clear the file without the need to close both streams temporarily, clear file, and reopen them again?
I have 2 applications, one is writing to a file, and the other one reads the file. It's a log file, so the writer will be logging until the program stops, while the reader could be invoked any time to get the content of the file.
I thought that when the writer opens the file with FileShare.Read, the reader would be able to access the file, but it produces an error saying that the file is being used by another process.
Writer Application:
FileStream fs = new FileStream("file.log", FileMode.Open, FileAccess.Write, FileShare.Read);
BinaryWriter writer = new BinaryWriter(fs);
Reader Application:
BinaryReader reader = new BinaryReader(File.OpenRead("file.log"));
How do I prevent this error?
Can you try specifying FileShare.Read while reading the file also? Instead of directly using File.OpenRead use FileStream with this permission.
Also, for logging, you can use log4Net or any other free logging framework which manages logging so efficiently and we do not have to manage writing to files.
o read a locked file you are going to need to provide more flags for the FileStream.
Code such as below.
using (var reader = new FileStream("d:\\test.txt", FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
{
using (var binary = new BinaryReader(reader))
{
//todo: add your code
binary.Close();
}
reader.Close();
}
This would open the file for reading only with the share mode of read write. This can be tested with a small app. (Using streamreader\write instead of binary)
static Thread writer,
reader;
static bool abort = false;
static void Main(string[] args)
{
var fs = File.Create("D:\\test.txt");
fs.Dispose();
writer = new Thread(new ThreadStart(testWriteLoop));
reader = new Thread(new ThreadStart(testReadLoop));
writer.Start();
reader.Start();
Console.ReadKey();
abort = true;
}
static void testWriteLoop()
{
using (FileStream fs = new FileStream("d:\\test.txt", FileMode.Open, FileAccess.Write, FileShare.Read))
{
using (var writer = new StreamWriter(fs))
{
while (!abort)
{
writer.WriteLine(DateTime.Now.ToString());
writer.Flush();
Thread.Sleep(1000);
}
}
}
}
static void testReadLoop()
{
while (!abort)
{
Thread.Sleep(1000);
using (var reader = new FileStream("d:\\test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var stream = new StreamReader(reader))
{
Console.WriteLine(stream.ReadToEnd());
stream.Close();
}
reader.Close();
}
}
}
I realize the example above is pretty simple but the fact still remains that the "testWriteLoop" never releases the lock.
Hope this helps
I get the following on the second using(StreamWriter statement:
Value does not fall within the expected range.
#region save allowance
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
//Open existing file
IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("foo.txt", FileMode.Truncate, FileAccess.Write);
using (StreamWriter writer = new StreamWriter(fileStream))
{
writer.Write(App.ViewModel.Foo);
}
#endregion
#region save log
IsolatedStorageFileStream fileStream2 = myIsolatedStorage.OpenFile("log.txt", FileMode.Truncate, FileAccess.Write);
using (StreamWriter writer = new StreamWriter(fileStream))
{
foreach( var i in App.ViewModel.Items )
writer.Write(i.ToString());
}
#endregion
You're reusing fileStream the second time instead of fileStream2. By the way, to avoid this kind of mistake, you may want to wrap your filestream inside the using block.
#region save allowance
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
//Open existing file
using (var writer = new StreamWriter(myIsolatedStorage.OpenFile("foo.txt", FileMode.Truncate, FileAccess.Write)))
{
writer.Write(App.ViewModel.Foo);
}
#endregion
#region save log
using (var writer = new StreamWriter(myIsolatedStorage.OpenFile("log.txt", FileMode.Truncate, FileAccess.Write)))
{
foreach( var i in App.ViewModel.Items )
writer.Write(i.ToString());
}
#endregion