or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcontexts.mdfile-operations.mdfilesystem.mdindex.mdlow-level-api.md

file-operations.mddocs/

0

# File and Directory Operations

1

2

Comprehensive file I/O operations and directory management capabilities including reading, writing, seeking, directory traversal, and extended attribute support. These operations provide both high-level Python semantics and low-level control over filesystem behavior.

3

4

## Capabilities

5

6

### FileHandle Class

7

8

Raw I/O file handle that extends Python's `io.RawIOBase` for direct binary file operations with LittleFS-specific optimizations.

9

10

```python { .api }

11

class FileHandle(io.RawIOBase):

12

def __init__(self, fs: LFSFilesystem, fh: LFSFile):

13

"""

14

Initialize file handle wrapper.

15

16

Parameters:

17

- fs: LFSFilesystem, filesystem object

18

- fh: LFSFile, low-level file handle

19

"""

20

21

def close(self) -> None:

22

"""

23

Close the file handle.

24

LittleFS automatically flushes on close.

25

"""

26

27

def readable(self) -> bool:

28

"""

29

Check if file is readable.

30

31

Returns:

32

bool: True if file was opened for reading

33

"""

34

35

def writable(self) -> bool:

36

"""

37

Check if file is writable.

38

39

Returns:

40

bool: True if file was opened for writing

41

"""

42

43

def seekable(self) -> bool:

44

"""

45

Check if file supports seeking.

46

47

Returns:

48

bool: Always True for LittleFS files

49

"""

50

51

def seek(self, offset: int, whence: int = io.SEEK_SET) -> int:

52

"""

53

Seek to position in file.

54

55

Parameters:

56

- offset: int, byte offset

57

- whence: int, seek reference (SEEK_SET, SEEK_CUR, SEEK_END)

58

59

Returns:

60

int: New absolute position

61

"""

62

63

def tell(self) -> int:

64

"""

65

Get current file position.

66

67

Returns:

68

int: Current byte position

69

"""

70

71

def truncate(self, size: int = None) -> int:

72

"""

73

Truncate file to specified size.

74

75

Parameters:

76

- size: int, new file size (default: current position)

77

78

Returns:

79

int: New file size

80

"""

81

82

def write(self, data: bytes) -> int:

83

"""

84

Write data to file.

85

86

Parameters:

87

- data: bytes, data to write

88

89

Returns:

90

int: Number of bytes written

91

"""

92

93

def readinto(self, b: bytearray) -> int:

94

"""

95

Read data into existing buffer.

96

97

Parameters:

98

- b: bytearray, buffer to read into

99

100

Returns:

101

int: Number of bytes read

102

"""

103

104

def readall(self) -> bytes:

105

"""

106

Read all remaining data from current position.

107

108

Returns:

109

bytes: All data from current position to end of file

110

"""

111

112

def flush(self) -> None:

113

"""

114

Flush file buffers to storage.

115

"""

116

```

117

118

### File I/O Operations

119

120

High-level file operations integrated with Python's I/O system.

121

122

```python { .api }

123

# File opening with Python semantics (from LittleFS class)

124

def open(self, fname: str, mode="r", buffering: int = -1, encoding: str = None,

125

errors: str = None, newline: str = None):

126

"""

127

Open file with full Python I/O stack integration.

128

129

Mode combinations:

130

- 'r': read only (default)

131

- 'w': write only, truncate existing

132

- 'a': write only, append to end

133

- 'x': write only, fail if exists

134

- '+': read and write

135

- 'b': binary mode

136

- 't': text mode (default)

137

138

Returns TextIOWrapper, BufferedReader, BufferedWriter, or FileHandle

139

based on mode and buffering settings.

140

"""

141

```

142

143

### Directory Management

144

145

Directory creation, listing, and navigation operations.

146

147

```python { .api }

148

# High-level directory operations (from LittleFS class)

149

def listdir(self, path=".") -> List[str]:

150

"""List directory contents as filename strings."""

151

152

def scandir(self, path="."):

153

"""Scan directory yielding LFSStat objects with full metadata."""

154

155

def mkdir(self, path: str) -> int:

156

"""Create single directory."""

157

158

def makedirs(self, name: str, exist_ok=False):

159

"""Create directory tree recursively."""

160

161

def rmdir(self, path: str) -> int:

162

"""Remove empty directory."""

163

164

def removedirs(self, name):

165

"""Remove directory tree upward while empty."""

166

167

def walk(self, top: str):

168

"""Walk directory tree yielding (root, dirs, files) tuples."""

169

170

# Low-level directory operations (from lfs module)

171

def dir_open(fs: LFSFilesystem, path: str) -> LFSDirectory:

172

"""Open directory for manual iteration."""

173

174

def dir_read(fs: LFSFilesystem, dh: LFSDirectory) -> Optional[LFSStat]:

175

"""Read next directory entry, None when exhausted."""

176

177

def dir_close(fs: LFSFilesystem, dh: LFSDirectory) -> int:

178

"""Close directory handle."""

179

180

def dir_tell(fs: LFSFilesystem, dh: LFSDirectory) -> int:

181

"""Get current directory iteration position."""

182

183

def dir_rewind(fs: LFSFilesystem, dh: LFSDirectory) -> int:

184

"""Reset directory iteration to beginning."""

185

```

186

187

### Path Operations

188

189

File and directory manipulation at the path level.

190

191

```python { .api }

192

# High-level path operations (from LittleFS class)

193

def remove(self, path: str, recursive: bool = False) -> None:

194

"""

195

Remove file or directory with optional recursive deletion.

196

197

Parameters:

198

- path: str, path to remove

199

- recursive: bool, remove directory contents recursively

200

"""

201

202

def rename(self, src: str, dst: str) -> int:

203

"""Rename or move file/directory."""

204

205

def stat(self, path: str) -> LFSStat:

206

"""Get file/directory status information."""

207

208

def unlink(self, path: str) -> int:

209

"""Remove file (alias for remove)."""

210

211

# Low-level path operations (from lfs module)

212

def remove(fs: LFSFilesystem, path: str) -> int:

213

"""Remove file or empty directory."""

214

215

def rename(fs: LFSFilesystem, oldpath: str, newpath: str) -> int:

216

"""Rename or move file/directory."""

217

218

def stat(fs: LFSFilesystem, path: str) -> LFSStat:

219

"""Get file/directory status."""

220

```

221

222

### Extended Attributes

223

224

Metadata storage and retrieval for files and directories.

225

226

```python { .api }

227

# High-level attribute operations (from LittleFS class)

228

def getattr(self, path: str, typ: Union[str, bytes, int]) -> bytes:

229

"""

230

Get extended attribute value.

231

232

Parameters:

233

- path: str, file or directory path

234

- typ: str/bytes/int, attribute type identifier (converted to 0-255 range)

235

236

Returns:

237

bytes: Attribute data

238

"""

239

240

def setattr(self, path: str, typ: Union[str, bytes, int], data: bytes) -> None:

241

"""

242

Set extended attribute value.

243

244

Parameters:

245

- path: str, file or directory path

246

- typ: str/bytes/int, attribute type identifier (converted to 0-255 range)

247

- data: bytes, attribute data to store

248

"""

249

250

def removeattr(self, path: str, typ: Union[str, bytes, int]) -> None:

251

"""

252

Remove extended attribute.

253

254

Parameters:

255

- path: str, file or directory path

256

- typ: str/bytes/int, attribute type identifier (converted to 0-255 range)

257

"""

258

259

# Low-level attribute operations (from lfs module)

260

def getattr(fs: LFSFilesystem, path: str, typ: int) -> bytes:

261

"""Get extended attribute (typ must be 0-255)."""

262

263

def setattr(fs: LFSFilesystem, path: str, typ: int, data: bytes) -> None:

264

"""Set extended attribute (typ must be 0-255)."""

265

266

def removeattr(fs: LFSFilesystem, path: str, typ: int) -> None:

267

"""Remove extended attribute (typ must be 0-255)."""

268

```

269

270

## File Status Information

271

272

```python { .api }

273

class LFSStat(NamedTuple):

274

"""File or directory status information."""

275

type: int # File type: LFS_TYPE_REG (1) or LFS_TYPE_DIR (2)

276

size: int # Size in bytes (0 for directories)

277

name: str # Filename without path

278

279

# Type constants

280

TYPE_REG = 1 # Regular file

281

TYPE_DIR = 2 # Directory

282

```

283

284

## Usage Examples

285

286

### Text File Operations

287

288

```python

289

from littlefs import LittleFS

290

291

fs = LittleFS(block_size=512, block_count=256)

292

293

# Write text file with automatic encoding

294

with fs.open('config.txt', 'w', encoding='utf-8') as f:

295

f.write('Configuration data\\n')

296

f.write('Setting: value\\n')

297

298

# Read text file with line iteration

299

with fs.open('config.txt', 'r', encoding='utf-8') as f:

300

for line_num, line in enumerate(f, 1):

301

print(f"Line {line_num}: {line.rstrip()}")

302

303

# Append to text file

304

with fs.open('config.txt', 'a', encoding='utf-8') as f:

305

f.write('Additional setting: new_value\\n')

306

```

307

308

### Binary File Operations

309

310

```python

311

import struct

312

313

# Write binary data

314

with fs.open('data.bin', 'wb') as f:

315

# Write header

316

f.write(struct.pack('<I', 0x12345678)) # Magic number

317

f.write(struct.pack('<H', 100)) # Record count

318

319

# Write records

320

for i in range(100):

321

f.write(struct.pack('<If', i, i * 1.5))

322

323

# Read binary data with seeking

324

with fs.open('data.bin', 'rb') as f:

325

# Read header

326

magic = struct.unpack('<I', f.read(4))[0]

327

count = struct.unpack('<H', f.read(2))[0]

328

329

print(f"Magic: 0x{magic:08x}, Records: {count}")

330

331

# Seek to specific record

332

record_num = 50

333

f.seek(6 + record_num * 8) # Header size + record size

334

index, value = struct.unpack('<If', f.read(8))

335

print(f"Record {record_num}: index={index}, value={value}")

336

```

337

338

### Directory Tree Operations

339

340

```python

341

# Create complex directory structure

342

fs.makedirs('project/src/main', exist_ok=True)

343

fs.makedirs('project/src/test', exist_ok=True)

344

fs.makedirs('project/docs', exist_ok=True)

345

346

# Create files in structure

347

files_to_create = [

348

'project/README.txt',

349

'project/src/main/app.py',

350

'project/src/main/utils.py',

351

'project/src/test/test_app.py',

352

'project/docs/manual.txt'

353

]

354

355

for filepath in files_to_create:

356

with fs.open(filepath, 'w') as f:

357

f.write(f'Content of {filepath}\\n')

358

359

# Walk entire tree

360

print("Complete directory tree:")

361

for root, dirs, files in fs.walk('project'):

362

level = root.count('/') - 1

363

indent = ' ' * level

364

print(f'{indent}{root}/')

365

366

sub_indent = ' ' * (level + 1)

367

for file in files:

368

stat_info = fs.stat(f"{root}/{file}")

369

print(f'{sub_indent}{file} ({stat_info.size} bytes)')

370

```

371

372

### Low-Level Directory Iteration

373

374

```python

375

from littlefs import lfs

376

377

# Manual directory iteration with full control

378

cfg = lfs.LFSConfig(block_size=512, block_count=256)

379

fs_obj = lfs.LFSFilesystem()

380

lfs.format(fs_obj, cfg)

381

lfs.mount(fs_obj, cfg)

382

383

# Create test files

384

lfs.mkdir(fs_obj, 'test_dir')

385

fh = lfs.file_open(fs_obj, 'test_dir/file1.txt', 'w')

386

lfs.file_write(fs_obj, fh, b'content1')

387

lfs.file_close(fs_obj, fh)

388

389

# Iterate manually

390

dh = lfs.dir_open(fs_obj, 'test_dir')

391

entries = []

392

393

while True:

394

entry = lfs.dir_read(fs_obj, dh)

395

if entry is None:

396

break

397

if entry.name not in ['.', '..']:

398

entries.append(entry)

399

400

lfs.dir_close(fs_obj, dh)

401

402

for entry in entries:

403

type_str = 'file' if entry.type == lfs.LFSStat.TYPE_REG else 'dir'

404

print(f"{entry.name}: {type_str}, {entry.size} bytes")

405

```

406

407

### Extended Attributes Usage

408

409

```python

410

# Store metadata with files

411

fs.mkdir('media')

412

413

# Create media file with metadata

414

with fs.open('media/photo.jpg', 'wb') as f:

415

f.write(b'\\xff\\xd8\\xff\\xe0') # JPEG header

416

417

# Store extended attributes

418

fs.setattr('media/photo.jpg', 'mime-type', b'image/jpeg')

419

fs.setattr('media/photo.jpg', 'camera', b'Canon EOS R5')

420

fs.setattr('media/photo.jpg', 'iso', b'800')

421

fs.setattr('media/photo.jpg', 'created', b'2024-01-15T10:30:00Z')

422

423

# Read metadata

424

mime_type = fs.getattr('media/photo.jpg', 'mime-type').decode()

425

camera = fs.getattr('media/photo.jpg', 'camera').decode()

426

iso = fs.getattr('media/photo.jpg', 'iso').decode()

427

created = fs.getattr('media/photo.jpg', 'created').decode()

428

429

print(f"File: media/photo.jpg")

430

print(f"MIME Type: {mime_type}")

431

print(f"Camera: {camera}")

432

print(f"ISO: {iso}")

433

print(f"Created: {created}")

434

435

# Numeric attribute types

436

fs.setattr('media/photo.jpg', 1, b'width=1920') # Type 1: dimension info

437

fs.setattr('media/photo.jpg', 2, b'height=1080') # Type 2: dimension info

438

439

width_info = fs.getattr('media/photo.jpg', 1).decode()

440

height_info = fs.getattr('media/photo.jpg', 2).decode()

441

print(f"Dimensions: {width_info}, {height_info}")

442

```

443

444

### File Truncation and Sparse Files

445

446

```python

447

# Create file with specific size

448

with fs.open('sparse.dat', 'wb') as f:

449

f.write(b'Header data')

450

# Truncate to create sparse file structure

451

f.truncate(1024) # File now 1024 bytes, rest filled with zeros

452

453

# Verify size and read sparse content

454

stat_info = fs.stat('sparse.dat')

455

print(f"File size: {stat_info.size} bytes")

456

457

with fs.open('sparse.dat', 'rb') as f:

458

header = f.read(11) # Read header

459

f.seek(-10, 2) # Seek to 10 bytes from end

460

tail = f.read() # Read tail (should be zeros)

461

462

print(f"Header: {header}")

463

print(f"Tail: {tail}") # b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'

464

```