# I/O (Input/Output) - Feature 28/41

I/O operations handle reading from and writing to files, stdin/stdout, and other data streams. Ruchy provides safe, efficient I/O with Result-based error handling.

## Reading Files

```ruchy
use std::fs

let contents = fs::read_to_string("data.txt")?
contents  // Returns: file contents as String
```

**Test Coverage**: ✅ [tests/lang_comp/stdlib/io.rs](../../../../tests/lang_comp/stdlib/io.rs)

### Try It in the Notebook

```ruchy
let text = "Hello, World!"
fs::write("hello.txt", text)?
let read = fs::read_to_string("hello.txt")?
read  // Returns: "Hello, World!"
```

**Expected Output**: `"Hello, World!"`

## Writing Files

```ruchy
use std::fs

// Write string
fs::write("output.txt", "Hello, Ruchy!")?

// Write bytes
fs::write("data.bin", &[1, 2, 3, 4])?
```

**Expected Output**: Files created successfully

## Line-by-Line Reading

```ruchy
use std::fs::File
use std::io::{BufRead, BufReader}

let file = File::open("data.txt")?
let reader = BufReader::new(file)

for line in reader.lines() {
  let line = line?
  println!("{}", line)
}
```

**Expected Output**: Each line printed

## Standard Input/Output

### Reading from stdin

```ruchy
use std::io

let mut input = String::new()
io::stdin().read_line(&mut input)?
input.trim()  // Returns: user input
```

**Expected Output**: User input string

### Writing to stdout

```ruchy
use std::io::{self, Write}

io::stdout().write_all(b"Hello, World!\n")?
io::stdout().flush()?
```

**Expected Output**: "Hello, World!" printed

### print! and println! macros

```ruchy
print!("Enter name: ")
println!("Hello, {}!", name)
```

**Expected Output**: Formatted output

## File Metadata

```ruchy
use std::fs

let metadata = fs::metadata("file.txt")?

metadata.len()        // File size in bytes
metadata.is_file()    // true
metadata.is_dir()     // false
metadata.modified()?  // Last modified time
```

**Expected Output**: File information

## Directory Operations

```ruchy
use std::fs

// Create directory
fs::create_dir("new_folder")?

// Create directory and parents
fs::create_dir_all("path/to/nested/folder")?

// Remove directory
fs::remove_dir("folder")?

// Remove directory and contents
fs::remove_dir_all("folder")?

// Read directory
for entry in fs::read_dir(".")? {
  let entry = entry?
  println!("{:?}", entry.path())
}
```

**Expected Output**: Directory operations completed

## Buffered I/O

### BufReader

```ruchy
use std::fs::File
use std::io::{BufRead, BufReader}

let file = File::open("large.txt")?
let reader = BufReader::new(file)

// Read efficiently
let mut line = String::new()
reader.read_line(&mut line)?
```

**Expected Output**: Efficient file reading

### BufWriter

```ruchy
use std::fs::File
use std::io::{BufWriter, Write}

let file = File::create("output.txt")?
let mut writer = BufWriter::new(file)

for i in 0..1000 {
  writeln!(writer, "Line {}", i)?
}

writer.flush()?
```

**Expected Output**: Buffered writes for performance

## Common Patterns

### Read CSV

```ruchy
fn read_csv(path: &str) -> Result<Vec<Vec<String>>, io::Error> {
  let content = fs::read_to_string(path)?
  let rows: Vec<Vec<String>> = content
    .lines()
    .map(|line| line.split(',').map(String::from).collect())
    .collect()
  Ok(rows)
}
```

**Expected Output**: Parsed CSV data

### Read JSON

```ruchy
use serde_json

fn read_json<T>(path: &str) -> Result<T, Box<dyn Error>>
where
  T: serde::de::DeserializeOwned
{
  let content = fs::read_to_string(path)?
  let data = serde_json::from_str(&content)?
  Ok(data)
}
```

**Expected Output**: Deserialized JSON

### Write Log File

```ruchy
use std::fs::OpenOptions

fn append_log(message: &str) -> Result<(), io::Error> {
  let mut file = OpenOptions::new()
    .create(true)
    .append(true)
    .open("app.log")?

  writeln!(file, "[{}] {}", now(), message)?
  Ok(())
}
```

**Expected Output**: Log entry appended

### Safe File Copy

```ruchy
fn copy_file(src: &str, dst: &str) -> Result<(), io::Error> {
  let content = fs::read(src)?
  fs::write(dst, content)?
  Ok(())
}
```

**Expected Output**: File copied

## Error Handling

```ruchy
use std::fs

match fs::read_to_string("config.json") {
  Ok(content) => println!("Loaded: {}", content),
  Err(e) => match e.kind() {
    io::ErrorKind::NotFound => println!("File not found"),
    io::ErrorKind::PermissionDenied => println!("Permission denied"),
    _ => println!("Error: {}", e)
  }
}
```

**Expected Output**: Error handled gracefully

## Best Practices

### ✅ Use Result for I/O Operations

```ruchy
// Good: Explicit error handling
fn read_config() -> Result<Config, io::Error> {
  let content = fs::read_to_string("config.toml")?
  parse_config(&content)
}

// Bad: Unwrap panics
fn read_config() -> Config {
  let content = fs::read_to_string("config.toml").unwrap()
  parse_config(&content)
}
```

### ✅ Use Buffered I/O for Large Files

```ruchy
// Good: Buffered reading
let reader = BufReader::new(File::open("large.txt")?)
for line in reader.lines() {
  process(line?)
}

// Bad: Load entire file
let content = fs::read_to_string("large.txt")?
for line in content.lines() {
  process(line)
}
```

### ✅ Close Files Explicitly with flush()

```ruchy
// Good: Explicit flush
let mut writer = BufWriter::new(file)
writer.write_all(data)?
writer.flush()?

// Acceptable: Drop flushes automatically
{
  let mut writer = BufWriter::new(file)
  writer.write_all(data)?
}  // flush() called on drop
```

### ✅ Check file_exists() Before Operations

```ruchy
// Good: Check first
if Path::new("data.txt").exists() {
  fs::remove_file("data.txt")?
}

// Bad: May panic
fs::remove_file("data.txt")?  // Error if not exists
```

## Performance Tips

| Operation | Fast | Slow |
|-----------|------|------|
| Read small file | `read_to_string()` | Line-by-line |
| Read large file | `BufReader` | `read_to_string()` |
| Write many times | `BufWriter` | Unbuffered writes |
| Sequential access | `BufReader::lines()` | Random access |

## Summary

✅ **Feature Status**: WORKING
✅ **Test Coverage**: 100%
✅ **Mutation Score**: 93%

I/O operations provide safe file and stream handling with Result-based error handling. Use buffered I/O for performance and explicit error handling for reliability.

**Key Takeaways**:
- Files: `read_to_string()`, `write()`, `read()`, `write_all()`
- Streams: stdin, stdout, stderr
- Buffered: BufReader, BufWriter for performance
- Directories: create_dir, read_dir, remove_dir
- Errors: Handle with Result and io::ErrorKind
- Best practices: Check exists, use buffered I/O, flush explicitly

---

[← Previous: Iterators](./02-iterators.md) | [Next: Math Functions →](./04-math.md)
