I am trying to read/write files using ReadBytemethod. code is working but I have noticed that they are not available after process.I cant open them.I images not displaying.what am i doing wrong again and again.
if (openFileDialog1.ShowDialog() == DialogResult.OK) {
if (saveFileDialog1.ShowDialog() == DialogResult.OK) {
FileStream fsRead =
new FileStream(openFileDialog1.FileName, FileMode.Open);
FileStream fswrite =
new FileStream(saveFileDialog1.FileName, FileMode.Create);
if (fsRead.Position != fsRead.Length) {
byte b = (byte)fsRead.ReadByte();
fswrite.WriteByte(b);
}
}
}
You're only reading a single byte - I suspect you meant to write a while loop instead of an if statement:
while (fsRead.Position != fsRead.Length) {
byte b = (byte)fsRead.ReadByte();
fswrite.WriteByte(b);
}
However, that's still not very efficient. Typically it's better to read and write chunks at a time, using "I can't read any more" to indicate the end of the file:
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = fsRead.Read(buffer, 0, buffer.Length)) > 0) {
fswrite.Write(buffer, 0, bytesRead);
}
However, you don't really need to do this yourself, as you can use Stream.CopyTo to do it for you:
fsRead.CopyTo(fswrite);
Note that you should also use using statements for your streams, to close them automatically at the end of the statement. I'd also use File.OpenWrite and File.OpenRead rather than calling the FileStream constructor, and just use a Stream variable:
using (Stream read = File.OpenRead(openFileDialog1.FileName),
write = File.OpenWrite(saveFileDialog1.FileName))
{
read.CopyTo(write);
}
Or just use File.Copy of course!
You need to close files after using, they are locked until that.
Best practice is to use using (var fs = new FileStream(...) { ... } construct - in that case, file streams and underlying files will be closed after using scope is finished.
So it should be something like this:
if (openFileDialog1.ShowDialog() == DialogResult.OK) {
if (saveFileDialog1.ShowDialog() == DialogResult.OK) {
using (FileStream fsRead = new FileStream(openFileDialog1.FileName, FileMode.Open))
using (FileStream fswrite = new FileStream(saveFileDialog1.FileName, FileMode.Create)) {
// your logic here
if (fsRead.Position != fsRead.Length) {
byte b = (byte)fsRead.ReadByte();
fswrite.WriteByte(b);
}
}
}
Related
I want to read file continuously like GNU tail with "-f" param. I need it to live-read log file.
What is the right way to do it?
More natural approach of using FileSystemWatcher:
var wh = new AutoResetEvent(false);
var fsw = new FileSystemWatcher(".");
fsw.Filter = "file-to-read";
fsw.EnableRaisingEvents = true;
fsw.Changed += (s,e) => wh.Set();
var fs = new FileStream("file-to-read", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (var sr = new StreamReader(fs))
{
var s = "";
while (true)
{
s = sr.ReadLine();
if (s != null)
Console.WriteLine(s);
else
wh.WaitOne(1000);
}
}
wh.Close();
Here the main reading cycle stops to wait for incoming data and FileSystemWatcher is used just to awake the main reading cycle.
You want to open a FileStream in binary mode. Periodically, seek to the end of the file minus 1024 bytes (or whatever), then read to the end and output. That's how tail -f works.
Answers to your questions:
Binary because it's difficult to randomly access the file if you're reading it as text. You have to do the binary-to-text conversion yourself, but it's not difficult. (See below)
1024 bytes because it's a nice convenient number, and should handle 10 or 15 lines of text. Usually.
Here's an example of opening the file, reading the last 1024 bytes, and converting it to text:
static void ReadTail(string filename)
{
using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Seek 1024 bytes from the end of the file
fs.Seek(-1024, SeekOrigin.End);
// read 1024 bytes
byte[] bytes = new byte[1024];
fs.Read(bytes, 0, 1024);
// Convert bytes to string
string s = Encoding.Default.GetString(bytes);
// or string s = Encoding.UTF8.GetString(bytes);
// and output to console
Console.WriteLine(s);
}
}
Note that you must open with FileShare.ReadWrite, since you're trying to read a file that's currently open for writing by another process.
Also note that I used Encoding.Default, which in US/English and for most Western European languages will be an 8-bit character encoding. If the file is written in some other encoding (like UTF-8 or other Unicode encoding), It's possible that the bytes won't convert correctly to characters. You'll have to handle that by determining the encoding if you think this will be a problem. Search Stack overflow for info about determining a file's text encoding.
If you want to do this periodically (every 15 seconds, for example), you can set up a timer that calls the ReadTail method as often as you want. You could optimize things a bit by opening the file only once at the start of the program. That's up to you.
To continuously monitor the tail of the file, you just need to remember the length of the file before.
public static void MonitorTailOfFile(string filePath)
{
var initialFileSize = new FileInfo(filePath).Length;
var lastReadLength = initialFileSize - 1024;
if (lastReadLength < 0) lastReadLength = 0;
while (true)
{
try
{
var fileSize = new FileInfo(filePath).Length;
if (fileSize > lastReadLength)
{
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
fs.Seek(lastReadLength, SeekOrigin.Begin);
var buffer = new byte[1024];
while (true)
{
var bytesRead = fs.Read(buffer, 0, buffer.Length);
lastReadLength += bytesRead;
if (bytesRead == 0)
break;
var text = ASCIIEncoding.ASCII.GetString(buffer, 0, bytesRead);
Console.Write(text);
}
}
}
}
catch { }
Thread.Sleep(1000);
}
}
I had to use ASCIIEncoding, because this code isn't smart enough to cater for variable character lengths of UTF8 on buffer boundaries.
Note: You can change the Thread.Sleep part to be different timings, and you can also link it with a filewatcher and blocking pattern - Monitor.Enter/Wait/Pulse. For me the timer is enough, and at most it only checks the file length every second, if the file hasn't changed.
This is my solution
static IEnumerable<string> TailFrom(string file)
{
using (var reader = File.OpenText(file))
{
while (true)
{
string line = reader.ReadLine();
if (reader.BaseStream.Length < reader.BaseStream.Position)
reader.BaseStream.Seek(0, SeekOrigin.Begin);
if (line != null) yield return line;
else Thread.Sleep(500);
}
}
}
so, in your code you can do
foreach (string line in TailFrom(file))
{
Console.WriteLine($"line read= {line}");
}
You could use the FileSystemWatcher class which can send notifications for different events happening on the file system like file changed.
private void button1_Click(object sender, EventArgs e)
{
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
path = folderBrowserDialog.SelectedPath;
fileSystemWatcher.Path = path;
string[] str = Directory.GetFiles(path);
string line;
fs = new FileStream(str[0], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
tr = new StreamReader(fs);
while ((line = tr.ReadLine()) != null)
{
listBox.Items.Add(line);
}
}
}
private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
string line;
line = tr.ReadLine();
listBox.Items.Add(line);
}
If you are just looking for a tool to do this then check out free version of Bare tail
I am trying to get a byte[] from a FileInfo.
Here, The FileInfo(fi) is a file I drop into my silverlight app.
So, as found on msnd, I am doing this :
byte[] b = new byte[fi.Length];
UTF8Encoding temp = new UTF8Encoding(true);
//Open the stream and read it back.
using (FileStream fs = fi.OpenRead())
{
while (fs.Read(b, 0, b.Length) > 0)
{
Console.WriteLine(temp.GetString(b));
}
}
But, do to it's protection level, I cannot use this.
So, I have done this :
byte[] b = new byte[fi.Length];
UTF8Encoding temp = new UTF8Encoding(true);
//Open the stream and read it back.
using (FileStream fs = fi.OpenRead())
{
while (fs.Read(b, 0, b.Length) > 0)
{
fs.Write(b, 0, b.Length);
}
}
But I got the message that I cannot Write from the FileStream.
Why I cannot write my File I drop into my app into a byte?
When The File is drop, it become a FileInfo.
Why I use OpenRead()? Because on the msdn, it seems it is writing the file : here
OpenWrite() rise an access error also.
Is there another way to do get yhe FileInfo document, into a byte?
To read a file into a byte[] the easies way would be:
byte[] myByteArray = File.ReadAllBytes(myFileInfo.FullName);
As #Dmitry Bychenko allready stated you try to write to a FileStream opened as readonly.
The other thing is that you want to write to the same FileStream you read from.
To solve the problem by correcting the attempt you did you can do:
byte[] b = new byte[fi.Length];
UTF8Encoding temp = new UTF8Encoding(true);
//Open the stream and read it back.
using (FileStream fs = fi.OpenRead())
{
using (MemoryStream ms = new MemoryStream(b))
{
while (fs.Read(b, 0, b.Length) > 0)
{
ms.Write(b, 0, b.Length);
}
}
}
In your case i would vote for the first example as its simple to read and hides the stream stuff perfectly.
I am trying to read/write files using FileStream. Code is working but After copied files all I get an empty file. String data inside the file is not copied.
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
if(saveFileDialog1.ShowDialog()==DialogResult.OK)
{
FileStream streamR = new FileStream(openFileDialog1.FileName, FileMode.Open);
byte[] buffer = new byte[streamR.Length];
streamR.Read(buffer, 0, buffer.Length);
FileStream streamW = new FileStream(saveFileDialog1.FileName,FileMode.Create);
int read_byte = 0;
while ((read_byte = streamR.Read(buffer, 0, buffer.Length)) > 0)
{
streamW.Write(buffer, 0, read_byte);
}
}
}
When using streams, you should use the 'using' command:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
if(saveFileDialog1.ShowDialog()==DialogResult.OK)
{
using (FileStream streamR = new FileStream(openFileDialog1.FileName, FileMode.Open))
{
using (FileStream streamW = new FileStream(saveFileDialog1.FileName,FileMode.Create))
{
byte[] buffer = new byte[streamR.Length];
int read_byte = 0;
while ((read_byte = streamR.Read(buffer, 0, buffer.Length)) > 0)
{
streamW.Write(buffer, 0, read_byte);
}
}
}
}
}
It will automatically flush, close and dispose the streams for you.
What actually stops your code from working, is the flush() and close() command.
However, it's still recommended to use the 'using' command.
A second way is to wrap everything in a try finally block and dispose the stream in the finally block:
using statement FileStream and / or StreamReader - Visual Studio 2012 Warnings
Anyway, I would suggest reading some more information about streams before continuing.
On the other hand ... if it's just for copying files, it would be simpler to use the Fil.Copy method.
Edit: Also ... loading the original file completely into a byte-array can cause some extra problems when your file is quite large.
The buffer is there to read chunks from the original file and process them.
I just corrected your code to make it work ... but it's far from perfect.
I would do something along these lines:
if (openFileDialog1.ShowDialog() == DialogResult.OK
&& saveFileDialog1.ShowDialog() == DialogResult.OK){
try {
if (File.Exists(saveFileDialog1.FileName)) {
File.Delete(saveFileDialog1.FileName);
}
File.Copy(openFileDialog1.FileName, saveFileDialog1.FileName);
} catch (Exception e){
//handle or throw e
}
}
I've got a rare case where a file cannot be read from a UNC path immediately after it was written. Here's the workflow:
plupload sends a large file in chunks to a WebAPI method
Method writes the chunks to a UNC path (a storage server). This loops until the file is completely uploaded.
After a few other operations, the same method tries to read the file again and sometimes it cannot find the file
It only seems to happen after our servers have been idle for a while. If I repeat the upload a few times, it starts to work.
I thought it might be a network configuration issue, or something to do with the file not completely closing before being read again.
Here's part of the code that writes the file (is the filestream OK in this case?)
SaveStream(stream, new FileStream(fileName, FileMode.Append, FileAccess.Write));
Here's SaveStream definition:
private static void SaveStream(Stream stream, FileStream fileStream)
{
using (var fs = fileStream)
{
var buffer = new byte[1024];
var l = stream.Read(buffer, 0, 1024);
while (l > 0)
{
fs.Write(buffer, 0, l);
l = stream.Read(buffer, 0, 1024);
}
fs.Flush();
fs.Close();
}
}
Here's the code that reads the file:
var fileInfo = new FileInfo(fileName);
var exists = fileInfo.Exists;
It's the fileInfo.Exists that is returning false.
Thank you
These kind of errors are mostly due to files not closed yet.
Try passing the fileName to SaveStream and then use it as follows:
private static void SaveStream(Stream stream, string fileName)
{
using (var fs = new FileStream(fileName, FileMode.Append, FileAccess.Write))
{
var buffer = new byte[1024];
var l = stream.Read(buffer, 0, 1024);
while (l > 0)
{
fs.Write(buffer, 0, l);
l = stream.Read(buffer, 0, 1024);
}
fs.Flush();
} // end of using will close and dispose fs properly
}
I want to read file continuously like GNU tail with "-f" param. I need it to live-read log file.
What is the right way to do it?
More natural approach of using FileSystemWatcher:
var wh = new AutoResetEvent(false);
var fsw = new FileSystemWatcher(".");
fsw.Filter = "file-to-read";
fsw.EnableRaisingEvents = true;
fsw.Changed += (s,e) => wh.Set();
var fs = new FileStream("file-to-read", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (var sr = new StreamReader(fs))
{
var s = "";
while (true)
{
s = sr.ReadLine();
if (s != null)
Console.WriteLine(s);
else
wh.WaitOne(1000);
}
}
wh.Close();
Here the main reading cycle stops to wait for incoming data and FileSystemWatcher is used just to awake the main reading cycle.
You want to open a FileStream in binary mode. Periodically, seek to the end of the file minus 1024 bytes (or whatever), then read to the end and output. That's how tail -f works.
Answers to your questions:
Binary because it's difficult to randomly access the file if you're reading it as text. You have to do the binary-to-text conversion yourself, but it's not difficult. (See below)
1024 bytes because it's a nice convenient number, and should handle 10 or 15 lines of text. Usually.
Here's an example of opening the file, reading the last 1024 bytes, and converting it to text:
static void ReadTail(string filename)
{
using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Seek 1024 bytes from the end of the file
fs.Seek(-1024, SeekOrigin.End);
// read 1024 bytes
byte[] bytes = new byte[1024];
fs.Read(bytes, 0, 1024);
// Convert bytes to string
string s = Encoding.Default.GetString(bytes);
// or string s = Encoding.UTF8.GetString(bytes);
// and output to console
Console.WriteLine(s);
}
}
Note that you must open with FileShare.ReadWrite, since you're trying to read a file that's currently open for writing by another process.
Also note that I used Encoding.Default, which in US/English and for most Western European languages will be an 8-bit character encoding. If the file is written in some other encoding (like UTF-8 or other Unicode encoding), It's possible that the bytes won't convert correctly to characters. You'll have to handle that by determining the encoding if you think this will be a problem. Search Stack overflow for info about determining a file's text encoding.
If you want to do this periodically (every 15 seconds, for example), you can set up a timer that calls the ReadTail method as often as you want. You could optimize things a bit by opening the file only once at the start of the program. That's up to you.
To continuously monitor the tail of the file, you just need to remember the length of the file before.
public static void MonitorTailOfFile(string filePath)
{
var initialFileSize = new FileInfo(filePath).Length;
var lastReadLength = initialFileSize - 1024;
if (lastReadLength < 0) lastReadLength = 0;
while (true)
{
try
{
var fileSize = new FileInfo(filePath).Length;
if (fileSize > lastReadLength)
{
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
fs.Seek(lastReadLength, SeekOrigin.Begin);
var buffer = new byte[1024];
while (true)
{
var bytesRead = fs.Read(buffer, 0, buffer.Length);
lastReadLength += bytesRead;
if (bytesRead == 0)
break;
var text = ASCIIEncoding.ASCII.GetString(buffer, 0, bytesRead);
Console.Write(text);
}
}
}
}
catch { }
Thread.Sleep(1000);
}
}
I had to use ASCIIEncoding, because this code isn't smart enough to cater for variable character lengths of UTF8 on buffer boundaries.
Note: You can change the Thread.Sleep part to be different timings, and you can also link it with a filewatcher and blocking pattern - Monitor.Enter/Wait/Pulse. For me the timer is enough, and at most it only checks the file length every second, if the file hasn't changed.
This is my solution
static IEnumerable<string> TailFrom(string file)
{
using (var reader = File.OpenText(file))
{
while (true)
{
string line = reader.ReadLine();
if (reader.BaseStream.Length < reader.BaseStream.Position)
reader.BaseStream.Seek(0, SeekOrigin.Begin);
if (line != null) yield return line;
else Thread.Sleep(500);
}
}
}
so, in your code you can do
foreach (string line in TailFrom(file))
{
Console.WriteLine($"line read= {line}");
}
You could use the FileSystemWatcher class which can send notifications for different events happening on the file system like file changed.
private void button1_Click(object sender, EventArgs e)
{
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
path = folderBrowserDialog.SelectedPath;
fileSystemWatcher.Path = path;
string[] str = Directory.GetFiles(path);
string line;
fs = new FileStream(str[0], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
tr = new StreamReader(fs);
while ((line = tr.ReadLine()) != null)
{
listBox.Items.Add(line);
}
}
}
private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
string line;
line = tr.ReadLine();
listBox.Items.Add(line);
}
If you are just looking for a tool to do this then check out free version of Bare tail