Потоки введення-виведення (I/O streams) у Ruby

В Ruby існують різні потоки введення-виведення (I/O streams), які можна використовувати залежно від завдань. Ось основні з них:

1. Стандартні потоки

Ці потоки створюються автоматично при запуску Ruby-програми:

  • STDIN – стандартний потік введення (зазвичай клавіатура).
  • STDOUT – стандартний потік виводу (зазвичай термінал/консоль).
  • STDERR – стандартний потік помилок (окремий від STDOUT, також термінал).

Приклад використання стандартних потоків:

puts "Це стандартний вивід"  # Виведе в STDOUT
STDERR.puts "Це помилка!"      # Виведе в STDERR
input = STDIN.gets            # Отримає введені дані з клавіатури

2. Файлові потоки (File)

Ruby дозволяє читати та писати у файли через File (який є підкласом IO).

Приклад запису у файл (альтернативний потік виводу):

file = File.open("output.txt", "w")
file.puts "Привіт, файл!"
file.close

Приклад читання з файлу (альтернативне джерело введення):

file = File.open("input.txt", "r")
puts file.gets  # Читає перший рядок з файлу
file.close

3. Конвеєри (IO.popen, Open3)

Дозволяють запускати зовнішні команди як потоки.

Приклад виконання команди ls і читання її виводу:

IO.popen("ls") do |io|
  puts io.read  # Читає вивід команди ls
end

А якщо потрібно отримати і STDOUT, і STDERR, можна використати Open3:

require 'open3'

stdout, stderr, status = Open3.capture3("ls /not_exist")
puts "STDOUT: #{stdout}"
puts "STDERR: #{stderr}"

4. Мережеві потоки (TCPSocket, TCPServer, UDPSocket)

Ruby дозволяє працювати з мережевими потоками через бібліотеку socket.

Приклад створення TCP-сокету та отримання даних:

require 'socket'

socket = TCPSocket.new('example.com', 80)
socket.puts "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
puts socket.read  # Читає відповідь сервера
socket.close

5. Віртуальні потоки (StringIO)

Іноді замість файлів зручно працювати з рядками, які поводяться як потоки.

Приклад використання StringIO:

require 'stringio'

io = StringIO.new("Привіт, StringIO!\nЩе один рядок")
puts io.gets  # Читає перший рядок
puts io.gets  # Читає другий рядок

6. Процеси (IO.pipe)

Використовується для зв’язку між процесами.

Приклад створення пайпа між процесами:

reader, writer = IO.pipe

fork do
  writer.puts "Привіт з дочірнього процесу!"
  writer.close
end

puts reader.gets  # Читає повідомлення з пайпа
reader.close

7. Стандартний NULL-потік (File::NULL)

Якщо потрібно відключити вивід або введення, можна спрямувати потік у /dev/null (Linux/macOS) або NUL (Windows).

Приклад ігнорування виводу:

File.open(File::NULL, "w") do |null|
  $stdout = null
  puts "Цей текст не з'явиться в консолі"
end

КОРОТКО ПРО ГОЛОВНЕ

Ruby підтримує різні потоки:

  1. Стандартні (STDIN, STDOUT, STDERR) – для введення, виводу та помилок.
  2. Файлові (File) – для роботи з файлами.
  3. Конвеєри (IO.popen, Open3) – для запуску зовнішніх команд.
  4. Мережеві (TCPSocket, TCPServer) – для обміну даними через інтернет.
  5. Віртуальні (StringIO) – для симуляції роботи з потоками у пам’яті.
  6. Міжпроцесні (IO.pipe) – для зв’язку між процесами.
  7. Null-потік (File::NULL) – для вимкнення введення або виводу.

PS Перші три категорії покривають понад 90% випадків роботи з потоками в Ruby. Решта (мережеві сокети, StringIO, пайпи між процесами) — це спеціалізовані інструменти, які потрібні рідше й у специфічних ситуаціях (наприклад, при розробці серверів, тестуванні або асинхронній обробці даних).