Більшість програм тим або іншим чином працюють із зовнішніми пристроями, наприклад, як консоль, файл на диску або мережене з'єднання. Взаємодія із зовнішніми пристроями організовується за допомогою потоків, які підтримуються множиною класів бібліотеки .NET.
Потік визначається як послідовність байтів і не залежить від конкретного пристрою, з яким проводиться обмін. Класи бібліотеки дозволяють працювати з потоками в різних режимах і на різних рівнях: на рівні двійкового представлення даних, байтів і тексту. Двійкові і байтові потоки зберігають дані у внутрішньому представленні, текстові - в кодуванні Unicode.
Потік можна відкрити в синхронному або асинхронному режимі для читання, запису або додавання. Доступ до файлів може бути послідовним і довільним. Текстові файли дозволяють виконувати тільки послідовний доступ, в двійкових і байтових потоках можна використовувати обидва методи. Прямий доступ у поєднанні з відсутністю перетворень забезпечує високу швидкість обміну.
Методи форматованого введення для значень арифметичних типів в С# не підтримуються. Для перетворення з символьного в числове представлення використовуються методи класу Convert або метод Parse. Форматоване виведення виконується за допомогою перевантаженого методу ToString, результат виконання якого передається в методи текстових файлів.
Рекомендується завжди перевіряти успішність відкриття існуючого файлу, перехоплювати виключення, що виникають при перетворенні значень арифметичних типів, і явним чином закривати файл, в який виконувався запис.
Тривалі операції з файлами ефективніше виконувати в асинхронному режимі.
Для збереження об'єктів (серіалізація) використовується атрибут [Serializable]. Об'єкти можна зберігати в одному з двох форматів: двійковому або SOAP (у вигляді XML-файла).