Read and write from/to the same line with BinaryReader/BinaryWriter - c#

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
{
}
}
}
}
}

Related

C# How to check if downloaded zip archive is corrupted ('End of Central Directory record could not be found' exception thrown)

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;
}
}

HowTo lock a file, read its content and overwrite it? [duplicate]

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
}
}

Binary reading data from exe file

I want to read data from exe file.
On java i read exe perfect from start to end,
bun on c# i cannot read all file.
File lenth is true but in result show only head of exe file
string fileLoc = filePaths[0];
FileStream fs = new FileStream(fileLoc, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader br = new BinaryReader(fs);
byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
foreach(byte b in bin){
Console.Write((char)b);
}
fs.Close();
output is only the head of exe: MZP
Cannot reproduce:
string fileLoc = //my path to git.exe
FileStream fs = new FileStream(fileLoc, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader br = new BinaryReader(fs);
byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
foreach (byte b in bin)
{
Console.Write((char)b);
}
fs.Close()
It writes all data from it.
But i see many problems in your code:
1) never do work with files with such unsafer way (if error occured file will not close) rewrite:
string fileLoc = //my path to git.exe
using(FileStream fs = new FileStream(fileLoc, FileMode.Open, FileAccess.Read, FileShare.Read)) {
BinaryReader br = new BinaryReader(fs);
byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
foreach (byte b in bin)
{
Console.Write((char)b);
}
} // no more explicit close required, but it will closed with guarantee
2) not mistake but in C# it's preferable use var (analoug to auto in c++)
using(var fs = new FileStream(fileLoc, FileMode.Open, FileAccess.Read, FileShare.Read)) {
var br = new BinaryReader(fs);
var bin = br.ReadBytes(Convert.ToInt32(fs.Length));
foreach (var b in bin)
{
Console.Write((char)b);
}
} //it still strong typed, but type referenced only once at right side of assigment
3) Not require use Convert for explicitly castable types (long->int)
var bin = br.ReadBytes((int)fs.Length);
4) I don't know why only MZP is written in your case, but can imagine that if you cast byte to char you will get many not-printable symbols including \r \n \f and so on in output - how your concrete terminal will be react? - i don't know
5) If you print (char)b just for test of bin - why so badly - why you not simply test bin.Length or why you print (char)b and not b+" " ? Otherwise if you really want to print bytes to console - it's bad idea anyway - look (4)
6) Why BinaryReader? if you just want read all
using(var fs = new FileStream(fileLoc, FileMode.Open, FileAccess.Read, FileShare.Read)) {
var bin = new byte[(int)fs.Length];
// u can use usual stream pattern
int l=0; while((l+=fs.Read(bin,t,bin.Length-t))<bin.Length);
foreach (var b in bin)
{
Console.Write((char)b);
}
}

File sharing for a separate writer and reader application in C#

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

Reading file content changes in .NET

In Linux, a lot of IPC is done by appending to a file in 1 process and reading the new content from another process.
I want to do the above in Windows/.NET (Too messy to use normal IPC such as pipes). I'm appending to a file from a Python process, and I want to read the changes and ONLY the changes each time FileSystemWatcher reports an event. I do not want to read the entire file content into memory each time I'm looking for changes (the file will be huge)
Each append operation appends a row of data that starts with a unique incrementing counter (timestamp+key) and ends with a newline.
using (FileStream fs = new FileStream
(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (someCondition)
{
while (!sr.EndOfStream)
ProcessLinr(sr.ReadLine());
while (sr.EndOfStream)
Thread.Sleep(100);
ProcessLinr(sr.ReadLine());
}
}
}
this will help you read only appended lines
You can store the offset of the last read operation and seek the file to that offset when you get a changed file notification. An example follows:
Main method:
public static void Main(string[] args)
{
File.WriteAllLines("test.txt", new string[] { });
new Thread(() => ReadFromFile()).Start();
WriteToFile();
}
Read from file method:
private static void ReadFromFile()
{
long offset = 0;
FileSystemWatcher fsw = new FileSystemWatcher
{
Path = Environment.CurrentDirectory,
Filter = "test.txt"
};
FileStream file = File.Open(
"test.txt",
FileMode.Open,
FileAccess.Read,
FileShare.Write);
StreamReader reader = new StreamReader(file);
while (true)
{
fsw.WaitForChanged(WatcherChangeTypes.Changed);
file.Seek(offset, SeekOrigin.Begin);
if (!reader.EndOfStream)
{
do
{
Console.WriteLine(reader.ReadLine());
} while (!reader.EndOfStream);
offset = file.Position;
}
}
}
Write to file method:
private static void WriteToFile()
{
for (int i = 0; i < 100; i++)
{
FileStream writeFile = File.Open(
"test.txt",
FileMode.Append,
FileAccess.Write,
FileShare.Read);
using (FileStream file = writeFile)
{
using (StreamWriter sw = new StreamWriter(file))
{
sw.WriteLine(i);
Thread.Sleep(100);
}
}
}
}

Categories

Resources