我正在异步读取三个文件并将它们写入一个文件中。 问题是它只写入LAST文件的内容。这是为什么? 我的代码:主要类:
public static FileReader filereader1= new FileReader("file1.txt");
public static FileReader filereader2 = new FileReader("file2.txt");
public static FileReader filereader3 = new FileReader("file3.txt");
public static FileWriter towrite = new FileWriter(writefile.txt");
public static void readFileAsync(object obj)
{
var filereader = obj as FileReader;
readf = new ReadFile(filereader.readLine);
if (filereader!=null)
{
while (!filereader.IsFinished)
{
IAsyncResult ar = readf.BeginInvoke(new AsyncCallback(myCallback),null);
}
}
}
public static void myCallback(IAsyncResult iar)
{
AsyncResult ar = (AsyncResult)iar;
ReadFile readf = (ReadFile)ar.AsyncDelegate;
string line = readf.EndInvoke(iar);
writefile.writeLine(line);
}
static void Main(string[] args)
{
readFileAsync(filereader1);
readFileAsync(filereader2);
readFileAsync(filereader3);
Console.ReadKey();
filereader1.Dispose();
filereader2.Dispose();
filereader3.Dispose();
writefile.Dispose();
} class FileReader:
public static StreamReader toRead { get; set; }
public string FilePath { get; set; }
public FileReader(string path)
{
FilePath = path;
toRead = new StreamReader(path);
}
public string ReadLine()
{
string line=null;
if (!toRead.EndOfStream)
{
line = toRead.ReadLine();
return line;
}
return null;
}
public bool IsFinished
{
get
{
if (toRead != null)
{
return toRead.EndOfStream;
}
return true;
}
}
public void Dispose()
{
if (toRead != null)
{
toRead.Close();
}
}
}
类FileWriter: {
public StreamWriter toWrite { get; set; }
public static object locker = new object();
public string FilePath { get; set; }
public FileWriter(string path)
{
FilePath = path;
toWrite = new StreamWriter(path);
}
public void writeLine(string line)
{
if (toWrite != null)
{
lock (locker)
{
toWrite.WriteLine(line);
}
}
}
public void Dispose()
{
if (toWrite != null)
{
toWrite.Close();
}
}
}
答案 0 :(得分:1)
将writefile设为单个实例,并在编写内容时应用同步锁。
public static void myCallback(IAsyncResult iar)
{
AsyncResult ar = (AsyncResult)iar;
ReadFile readf = (ReadFile)ar.AsyncDelegate;
string line = readf.EndInvoke(iar);
lock(obj)
{
writefile.writeLine(line);
successCount++;
}
}
private static object obj = new object();
private static int successCount = 0;
static void Main(string[] args)
{
readFileAsync(filereader1);
readFileAsync(filereader2);
readFileAsync(filereader3);
while(Console.ReadKey())
{
if(successCount == 3)
{
filereader1.Dispose();
filereader2.Dispose();
filereader3.Dispose();
writefile.Dispose();
break;
}
}
}
答案 1 :(得分:0)
是否有理由需要使用异步回调?
如果没有,请尝试这些方法。
TPL:
var tasks = new []
{
Task.Factory.StartNew(() => File.ReadAllText(@"file1.txt")),
Task.Factory.StartNew(() => File.ReadAllText(@"file2.txt")),
Task.Factory.StartNew(() => File.ReadAllText(@"file3.txt")),
};
Task.Factory.ContinueWhenAll(tasks, ts =>
{
var output = @"writefile.txt";
File.WriteAllText(output, ts[0].Result);
File.AppendAllText(output, ts[1].Result);
File.AppendAllText(output, ts[2].Result);
Console.WriteLine("Done.");
});
Microsoft Reactive Framework(Rx):
var write = @"writefile.txt";
File.WriteAllText(write, null);
new []
{
Observable.Start(() => File.ReadAllText(@"file1.txt")),
Observable.Start(() => File.ReadAllText(@"file2.txt")),
Observable.Start(() => File.ReadAllText(@"file3.txt")),
}
.Merge()
.Subscribe(
x => File.AppendAllText(write, x),
() => Console.WriteLine("Done."));
两者都异步读取文件并同步写入文件(没有覆盖!)。 TPL解决方案按文件顺序写入结果。 Rx保留文件读取的顺序。
您的代码在以下几行中存在严重问题:
while (!filereader.IsFinished)
{
IAsyncResult ar = readf.BeginInvoke(new AsyncCallback(myCallback),null);
}
异步尝试读取行,但它正在同步尝试确定您是否已经到达文件的末尾。这将尝试在第一个从文件读取之前触发许多异步调用。这段代码永远不会起作用。
您的代码的另一个问题是,FileReader
类中定义流的行已声明为static
。这需要定义如下:
public StreamReader toRead { get; set; }
现在我重新编写了代码来生成相当好的代码:
public static void readFileAsync(FileReader filereader)
{
var readf = new ReadFile(filereader.ReadLine);
Action<IAsyncResult> callBack = null;
callBack = iar =>
{
var line = readf.EndInvoke(iar);
writefile.writeLine(line);
if (!filereader.IsFinished)
{
readf.BeginInvoke(new AsyncCallback(callBack), null);
}
};
if (!filereader.IsFinished)
{
readf.BeginInvoke(new AsyncCallback(callBack), null);
}
}
只有在前一个读完成后才调用新的读取。
我也进行了彻底的重新设计,并将异步性更改为基于文件的,而不是基于行的。这也有效:
static void Main(string[] args)
{
using (var writefile = new FileWriter(@"writefile.txt"))
{
Action<string> readAndWrite= fn =>
{
using (var fr = new FileReader(fn))
{
while (!fr.IsFinished)
{
writefile.writeLine(fr.ReadLine());
}
}
};
AsyncCallback callBack = ar => { };
var ar1 = readAndWrite.BeginInvoke(@"file1.txt", callBack, null);
var ar2 = readAndWrite.BeginInvoke(@"file2.txt", callBack, null);
var ar3 = readAndWrite.BeginInvoke(@"file3.txt", callBack, null);
WaitHandle.WaitAll(new[]
{
ar1.AsyncWaitHandle,
ar2.AsyncWaitHandle,
ar3.AsyncWaitHandle,
});
}
}
}
希望这些建议有所帮助。