Если строки короткие, то, в принципе, подойдёт такое решение:
var secondFileLines = new HashSet<string>(File.ReadLines("<файл2>"));
using (var writer = new StreamWriter("<файл3>"))
{
foreach (var line in File.ReadLines("<файл1>"))
{
if (!secondFileLines.Contains(line))
{
writer.WriteLine(line);
}
}
}
Если длина строк неограничена, то могут возникнуть проблемы с расходом памяти. В этом случае, всё сильно усложняется. Вам, вероятно, придётся хранить набор хэш-кодов строк из второго файла и сравнивать с хэш-кодом каждой строки из первого. Но тут могут возникнуть ложно-положительные срабатывания, если у разных строк хэши будут совпадать. В этом случае, необходимо будет сравнивать строки посимвольно. Это при идеальной реализации. Впрочем, вероятность совпадения хэшей - 1/2^32. Ну, и надо умножить на 70 миллионов. Если задача позволяет добавить пару лишних строк в результирующий файл, я бы так и поступил.
Можно немного улучшить алгоритм с хэшами: если, например, использовать 256-битную хэш-функцию, а не стандартную (GetHashCode), можно снизить вероятность ложного срабатывания до 1e-77 (в случае использования SHA1). Думаю, такой мизерной вероятности будет достаточно, чтобы считать задачу решённой. Правда, придётся немного усложнить алгоритм сравнения хэшей - придётся сравнивать массивы.