Могу. Если кратко - всё будет работать. Если подробнее:
Не имеет значения как мы выйдем из цикла, через break или по исключению (в примере из статьи исключения не обрабатываются, это сделано чтобы не перегружать пример деталями). При завершении функции произойдет вызов return_void из promise_type, а затем произойдет вызов final_suspend. И туда и туда можно полезной логики навешать. Для последней интересный пример есть здесь.
После final_suspend корутина получит состочние done. Её выполнение уже нельзя будет возобновлять при помощи resume(), и будет необходимо освободить служебную память вызовом destroy(). Кстати, если final_suspend вернет suspend_never, destroy() будет вызван автоматически.
Что касается второй части вашего вопроса про потоки и файлы. Корутины, потоки и файлы живут, так сказать, в разных измерениях. Корутина будет вести себя точно так же, как вела бы себя функция, в которой co_yield заменили, к примеру, на std::cout <<. Корутина сохраняет локальные переменные не в стеке, а в куче. Поэтому они замечательно живут между вызовами co_yield или co_await