0
# File Operations
1
2
File reading and writing operations for handling individual files and file collections. These methods provide direct access to Metalsmith's file I/O system for custom processing workflows.
3
4
## Capabilities
5
6
### Read Directory
7
8
Read all files from a directory, parsing front-matter and creating file objects.
9
10
```javascript { .api }
11
/**
12
* Read files from directory (Promise version)
13
* @param directory - Directory to read (defaults to source directory)
14
* @returns Promise resolving to Files object
15
*/
16
read(directory?: string): Promise<Files>;
17
18
/**
19
* Read files from directory (callback version)
20
* @param directory - Directory to read (defaults to source directory)
21
* @param callback - Callback receiving error and files
22
*/
23
read(directory: string, callback: FileCallback): void;
24
25
type FileCallback = (error: Error | null, files: Files) => void;
26
```
27
28
**Usage Examples:**
29
30
```javascript
31
import Metalsmith from "metalsmith";
32
33
const metalsmith = Metalsmith(__dirname);
34
35
// Read from default source directory
36
const files = await metalsmith.read();
37
console.log(`Read ${Object.keys(files).length} files`);
38
39
// Read from specific directory
40
const templateFiles = await metalsmith.read('./templates');
41
42
// Callback version
43
metalsmith.read((error, files) => {
44
if (error) throw error;
45
Object.keys(files).forEach(filepath => {
46
console.log(`File: ${filepath}`);
47
console.log(`Size: ${files[filepath].contents.length} bytes`);
48
});
49
});
50
```
51
52
### Read Single File
53
54
Read a single file by path, parsing front-matter if enabled.
55
56
```javascript { .api }
57
/**
58
* Read single file by path (Promise version)
59
* @param filepath - File path (relative to source directory or absolute)
60
* @returns Promise resolving to File object
61
*/
62
readFile(filepath: string): Promise<File>;
63
64
/**
65
* Read single file by path (callback version)
66
* @param filepath - File path (relative to source directory or absolute)
67
* @param callback - Callback receiving error and file
68
*/
69
readFile(filepath: string, callback: SingleFileCallback): void;
70
71
type SingleFileCallback = (error: Error | null, file?: File) => void;
72
```
73
74
**Usage Examples:**
75
76
```javascript
77
// Read specific file
78
const indexFile = await metalsmith.readFile('index.md');
79
console.log('Title:', indexFile.title);
80
console.log('Content:', indexFile.contents.toString());
81
82
// Read with absolute path
83
const configFile = await metalsmith.readFile('/path/to/config.json');
84
85
// Callback version
86
metalsmith.readFile('about.md', (error, file) => {
87
if (error) {
88
console.error('Failed to read file:', error.message);
89
return;
90
}
91
92
console.log('File metadata:', {
93
title: file.title,
94
date: file.date,
95
size: file.contents.length
96
});
97
});
98
```
99
100
### Write Files
101
102
Write a collection of files to the destination directory.
103
104
```javascript { .api }
105
/**
106
* Write files to destination directory (Promise version)
107
* @param files - Files object to write
108
* @param directory - Target directory (defaults to destination directory)
109
* @returns Promise that resolves when writing is complete
110
*/
111
write(files: Files, directory?: string): Promise<void>;
112
113
/**
114
* Write files to directory (callback version)
115
* @param files - Files object to write
116
* @param directory - Target directory (defaults to destination directory)
117
* @param callback - Callback for completion
118
*/
119
write(files: Files, directory: string, callback: BuildCallback): void;
120
121
/**
122
* Write files with callback only
123
* @param files - Files object to write
124
* @param callback - Callback for completion
125
*/
126
write(files: Files, callback: BuildCallback): void;
127
```
128
129
**Usage Examples:**
130
131
```javascript
132
// Write processed files to default destination
133
const files = await metalsmith.read();
134
// ... process files with plugins
135
await metalsmith.write(files);
136
137
// Write to specific directory
138
await metalsmith.write(files, './output');
139
140
// Callback version
141
metalsmith.write(files, (error) => {
142
if (error) {
143
console.error('Write failed:', error.message);
144
return;
145
}
146
console.log('Files written successfully');
147
});
148
```
149
150
### Write Single File
151
152
Write a single file to the destination directory.
153
154
```javascript { .api }
155
/**
156
* Write single file (Promise version)
157
* @param filepath - Target file path (relative to destination or absolute)
158
* @param data - File object to write
159
* @returns Promise that resolves when writing is complete
160
*/
161
writeFile(filepath: string, data: File): Promise<void>;
162
163
/**
164
* Write single file (callback version)
165
* @param filepath - Target file path (relative to destination or absolute)
166
* @param data - File object to write
167
* @param callback - Callback for completion
168
*/
169
writeFile(filepath: string, data: File, callback: ErrorCallback): void;
170
171
type ErrorCallback = (error: Error | null) => void;
172
```
173
174
**Usage Examples:**
175
176
```javascript
177
// Create and write a new file
178
const newFile = {
179
contents: Buffer.from('# New Page\n\nThis is content.'),
180
title: 'New Page',
181
date: new Date()
182
};
183
184
await metalsmith.writeFile('new-page.html', newFile);
185
186
// Write to specific location
187
await metalsmith.writeFile('/absolute/path/file.txt', {
188
contents: Buffer.from('File content')
189
});
190
191
// Callback version
192
metalsmith.writeFile('output.json', {
193
contents: Buffer.from(JSON.stringify(data, null, 2))
194
}, (error) => {
195
if (error) throw error;
196
console.log('JSON file written');
197
});
198
```
199
200
### File Object Structure
201
202
Understanding the File object structure for reading and writing operations.
203
204
```javascript { .api }
205
interface File {
206
/** File contents as Buffer (always present) */
207
contents: Buffer;
208
/** Node.js fs.Stats object with file system metadata */
209
stats?: import('fs').Stats;
210
/** Octal file permission mode (e.g., "0644") */
211
mode?: string;
212
/** Front-matter properties and custom metadata */
213
[key: string]: any;
214
}
215
216
interface Files {
217
/** File path mapped to File object */
218
[filepath: string]: File;
219
}
220
```
221
222
**File Manipulation Examples:**
223
224
```javascript
225
// Reading and modifying file contents
226
const files = await metalsmith.read();
227
228
Object.keys(files).forEach(filepath => {
229
const file = files[filepath];
230
231
// Access file contents
232
const content = file.contents.toString();
233
234
// Access front-matter data
235
console.log('Title:', file.title);
236
console.log('Date:', file.date);
237
console.log('Tags:', file.tags);
238
239
// Modify contents
240
file.contents = Buffer.from(content.toUpperCase());
241
242
// Add custom metadata
243
file.processedAt = new Date();
244
file.wordCount = content.split(/\s+/).length;
245
246
// Preserve file stats and mode
247
console.log('File size:', file.stats?.size);
248
console.log('File mode:', file.mode);
249
});
250
251
await metalsmith.write(files);
252
```
253
254
### Custom File Processing Workflows
255
256
Examples of custom workflows using file operations directly.
257
258
```javascript
259
// Custom build pipeline
260
async function customBuild() {
261
const metalsmith = Metalsmith(__dirname);
262
263
// Read source files
264
const sourceFiles = await metalsmith.read();
265
console.log(`Read ${Object.keys(sourceFiles).length} source files`);
266
267
// Read template files separately
268
const templates = await metalsmith.read('./templates');
269
console.log(`Read ${Object.keys(templates).length} templates`);
270
271
// Process files through plugins
272
const processedFiles = await metalsmith.run(sourceFiles);
273
274
// Write to multiple locations
275
await metalsmith.write(processedFiles, './public');
276
await metalsmith.write(processedFiles, './backup');
277
278
console.log('Custom build complete');
279
}
280
281
// Selective file processing
282
async function processSpecificFiles() {
283
const metalsmith = Metalsmith(__dirname);
284
285
// Read only markdown files
286
const allFiles = await metalsmith.read();
287
const markdownFiles = {};
288
289
Object.keys(allFiles)
290
.filter(filepath => filepath.endsWith('.md'))
291
.forEach(filepath => {
292
markdownFiles[filepath] = allFiles[filepath];
293
});
294
295
// Process only markdown files
296
const processed = await metalsmith.run(markdownFiles);
297
298
// Write processed files
299
await metalsmith.write(processed);
300
}
301
```
302
303
### Error Handling for File Operations
304
305
Common error scenarios and handling patterns.
306
307
```javascript
308
try {
309
const files = await metalsmith.read();
310
} catch (error) {
311
if (error.code === 'ENOENT') {
312
console.error('Source directory not found');
313
} else if (error.code === 'EACCES') {
314
console.error('Permission denied reading files');
315
} else if (error.code === 'invalid_frontmatter') {
316
console.error('Invalid front-matter in file:', error.message);
317
} else {
318
console.error('Read error:', error.message);
319
}
320
}
321
322
// Write error handling
323
try {
324
await metalsmith.write(files);
325
} catch (error) {
326
if (error.code === 'failed_write') {
327
console.error('Failed to write file:', error.message);
328
} else if (error.code === 'EACCES') {
329
console.error('Permission denied writing files');
330
} else {
331
console.error('Write error:', error.message);
332
}
333
}
334
```