После некоторого поиска я обнаружил, что FileSystemWatcher вызывает событие только после закрытия файла, как показано в этой статье . В статье упоминается только дата изменения NotifyFilter, но в моем тестировании я обнаружил, что все Notifyfilters срабатывают после закрытия файла и никогда, пока он еще открыт.
По этой причине, похоже, что следит за , файл возможен только с помощью зацикленной функции, которая непрерывно отслеживает файл на наличие дополнительных строк. Я использовал код этой ссылки в качестве примера.
Вот мой рабочий код:
[TestClass]
public class FileWriteTests
{
[TestMethod]
public void TestMethodAfterClose_filetailing()
{
var currentDir = Environment.CurrentDirectory;
var fileToMonitor = "test.txt";
File.Delete(Path.Combine(currentDir, fileToMonitor));
List output = new List();
using (var watcherTest = new PersonalFileTail(currentDir, fileToMonitor))
{
watcherTest.StartTail(delegate (string line) { output.Add(line); });
using (var writer = new StreamWriter(Path.Combine(currentDir, fileToMonitor), true))
{
writer.WriteLine($"test");
writer.Flush();
}
System.Threading.Thread.Sleep(200);
watcherTest.StopTail();
}
System.Threading.Thread.Sleep(10);
Assert.AreEqual(1, output.Count);
Assert.AreEqual("test", output[0]);
}
[TestMethod]
public void TestMethodAfterFlush_filetailing()
{
// initiate file
var currentDir = Environment.CurrentDirectory;
var fileToMonitor = "test.txt";
File.Delete(Path.Combine(currentDir, fileToMonitor));
FileInfo info = new FileInfo(Path.Combine(currentDir, fileToMonitor));
List output = new List();
using (var watcherTest = new PersonalFileTail(currentDir, fileToMonitor))
{
watcherTest.StartTail(delegate (string line) { output.Add(line); });
using (var writer = new StreamWriter(Path.Combine(currentDir, fileToMonitor), true))
{
try
{
writer.WriteLine($"test");
writer.Flush();
System.Threading.Thread.Sleep(1000);
Assert.AreEqual(1, output.Count);
Assert.AreEqual("test", output[0]);
}
catch
{
Assert.Fail("Test failed");
}
}
watcherTest.StopTail();
}
}
public class PersonalFileTail : IDisposable
{
private string filename;
private string directory;
private Task fileTailTask;
private Action handleResults;
private volatile bool runTask;
private long lastFilePosition;
public string FileName
{
get { return Path.Combine(directory, filename); }
}
public PersonalFileTail(string directory, string filename)
{
this.directory = directory;
this.filename = filename;
this.runTask = false;
lastFilePosition = 0;
}
public void StartTail(Action handleResults)
{
this.handleResults = handleResults;
runTask = true;
fileTailTask = Task.Run(() => MonitorFileTask());
}
public void StopTail()
{
runTask = false;
fileTailTask.Wait();
}
public IEnumerable ReadLinesFromFile()
{
using (StreamReader reader = new StreamReader(new FileStream(FileName,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
string line = "";
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
lastFilePosition = reader.BaseStream.Length;
}
}
public void MonitorFileTask()
{
StreamReader reader = null;
FileStream stream = null;
try
{
using(stream = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (reader = new StreamReader(stream))
{
do
{
//if the file size has increased do something
if (reader.BaseStream.Length > lastFilePosition)
{
//seek to the last max offset
reader.BaseStream.Seek(lastFilePosition, SeekOrigin.Begin);
//read out of the file until the EOF
string line = "";
while ((line = reader.ReadLine()) != null)
{
handleResults(line);
}
//update the last max offset
lastFilePosition = reader.BaseStream.Position;
}
// sleep task for 100 ms
System.Threading.Thread.Sleep(100);
}
while (runTask);
}
}
catch
{
if (reader != null)
reader.Dispose();
if (stream != null)
stream.Dispose();
}
}
public void Dispose()
{
if(runTask)
{
runTask = false;
fileTailTask.Wait();
}
}
}
}
Если кто-нибудь знает способ, которым можно выполнить хвостовую обработку без использования временной функции, я приму это в качестве ответа. До этого времени я чувствую, что мой ответ - единственный возможный способ сделать это.
Необходимо включить их для цикла, как Вы делаете. Конечно, Вы могли сделать класс и придерживаться к циклу в том классе.
Для некоторого большого implmentations Наборов в AS3 проверьте этих парней.
Отредактируйте 2013 Не удивительно, ссылки действительно повреждаются после времени. Попробуйте этот новый: http://www.grindheadgames.com/get-the-length-of-an-object.
Выполнение нескольких тестов на этом на самом деле удивило меня. Вот нормальная эксплуатация Массива:
var things:Array = [];
things.push("hi!");
trace(things.length);
// traces 1
trace(things);
// traces hi!
Вот то, если мы устанавливаем значение к строке:
var things:Array = [];
things["thing"] = "hi!";
trace(things.length);
// traces 0
trace(things);
// traces an empty string
trace(things["thing"]);
// traces hi!
В основном, если Вы добавляете вещи с помощью строк, Вы устанавливаете свойства вместо того, чтобы на самом деле добавить к массиву. Заставляет меня задаться вопросом, почему Массив является динамическим таким образом.
Так... да считайте объекты с для... в цикле!
var count:int;
var key:String;
for (key in myObject)
{
count++;
}
trace ("myObject has this many keys in it: " + count);
или, альтернативно, для - каждый синтаксис (я не протестировал для наблюдения, который быстрее),
for each (var o:* in myObject)
{
count++;
}
Я думаю, что Вы застреваете с подсчетом их "вручную".
Опция состояла бы в том, чтобы перенести все это в класс и сохранить отдельную переменную, которую Вы обновляете, как Вы добавляете/удаляете.