我假设你的例子中可能会有更多的数据.如果您可以同时打开所有文件,则可以使用此算法:
请注意,您不必一次将所有文件读入内存,因此如果您有合理数量的大文件,这将很有效,但如果您有大量小文件则不行.
如果您有许多小文件,则应将它们合并为组以为每个组创建单个输出文件,然后重复此过程以合并这些新组.
在C#中,您可以使用例如a SortedDictionary来实现优先级队列.
在另一个答案中解决评论:
如果您有可变数量的文件,这就是我要做的.这只是一个草图,以实现这个想法; 这段代码没有编译,我的方法名称错了,等等.
// initialize the data structures
var priorityQueue = new SortedDictionary<Record, Stream>();
var streams = new List<Stream>();
var outStream = null;
try
{
// open the streams.
outStream = OpenOutputStream();
foreach(var filename in filenames)
streams.Add(GetFileStream(filename));
// initialize the priority queue
foreach(var stream in streams)
{
var record = ReadRecord(stream);
if (record != null)
priorityQueue.Add(record, stream);
// the main loop
while(!priorityQueue.IsEmpty)
{
var record = priorityQueue.Smallest;
var smallestStream = priorityQueue[record];
WriteRecord(record, outStream);
priorityQueue.Remove(record);
var newRecord = ReadRecord(smallestStream);
if (newRecord != null)
priorityQueue.Add(newRecord, smallestStream);
}
}
finally { clean up the streams }
Run Code Online (Sandbox Code Playgroud)
那有意义吗?您只需继续从优先级队列中抓取最小的东西,并将其替换为该流中的下一条记录(如果有的话).最终队列将为空,您将完成.
策略可能取决于数据量。
下面是一个代码示例,它读取 N 个排序的文本文件并合并它们。我没有包括重复检查,但它应该很容易实现。
首先是一个助手类。
class MergeFile : IEnumerator<string>
{
private readonly StreamReader _reader;
public MergeFile(string file)
{
_reader = File.OpenText(file);
Current = _reader.ReadLine();
}
public string Current { get; set; }
public void Dispose()
{
_reader.Close();
}
public bool MoveNext()
{
Current = _reader.ReadLine();
return Current != null;
}
public void Reset()
{
throw new NotImplementedException();
}
object IEnumerator.Current
{
get { return Current; }
}
}
Run Code Online (Sandbox Code Playgroud)
然后是读取和合并的代码(为了在生产中清晰起见,应该对其进行重构):
// Get the file names and instantiate our helper class
List<IEnumerator<string>> files = Directory.GetFiles(@"C:\temp\files", "*.txt").Select(file => new MergeFile(file)).Cast<IEnumerator<string>>().ToList();
List<string> result = new List<string>();
IEnumerator<string> next = null;
while (true)
{
bool done = true;
// loop over the helpers
foreach (var mergeFile in files)
{
done = false;
if (next == null || string.Compare(mergeFile.Current, next.Current) < 1)
{
next = mergeFile;
}
}
if (done) break;
result.Add(next.Current);
if (!next.MoveNext())
{
// file is exhausted, dispose and remove from list
next.Dispose();
files.Remove(next);
next = null;
}
}
Run Code Online (Sandbox Code Playgroud)