File
An open file.
Returned by open and Path.open.
Every operation on a closed file raises
StateError.
A file is both an iterator and a sink, so it can be used with for,
.next(), .put(), and strand.redirect. The open mode fixes which for the
file's lifetime: a text-mode file yields and accepts lines, a binary-mode one
arbitrary chunks. In either mode the values read from a file concatenate back
to exactly the file's bytes.
Inherits from: Iter[Str | Bin], Sink[Value]
Methods
(iter)() -> File
Returns the file as its own iterator.
(next)() -> (Str | Bin)
Fetches the next value from the file.
In text mode this reads the next line as a Str,
including its terminator, so a \r\n file stays \r\n and a final
line without one yields a value without one. Use
chomp to strip them:
In binary mode it reads a chunk of data of arbitrary length.
(put) value
Writes a value to the file, verbatim.
A Str or Bin contributes its own
bytes and nothing else, and anything else is converted to a string first.
No line ending is appended in either mode, and none is translated.
Use precrimp to terminate written values, with
shell.line_ending() for the target's
native ending:
Parameters
| Name | Type | Description |
|---|---|---|
value |
Value to write. |
(sink)() -> File
Returns the file as its own sink.
acl … -> (security.AnyAcl | nil)
Gets the ACL stored on the open file.
Parameters
| Name | Type | Description |
|---|---|---|
:kind? |
(:POSIX: | :NFS4: | :MACOS:) |
ACL format to query. Defaults to
:POSIX:. |
:default? |
Bool |
Query the directory's inheritable default ACL. |
Returns
The matching portable ACL type, depending on kind, or nil when no ACL
metadata is stored.
close()
Closes the file.
This is required if open was not given a block.
Closing a file that is already closed does nothing.
Passing a file to a child process as stdin:, stdout:, or stderr: also
closes it: the child receives the file itself, and the seek position is
kept by this process rather than by the operating system, so two live
handles would each believe a cursor the other moves. Use the file after the
handoff and it raises the ordinary closed-file error.
Example
copy_data dst … -> Int
The method form of fs.copy_data.
Parameters
| Name | Type | Description |
|---|---|---|
dst |
File |
Handle to write to. |
:range? |
Range[Int] |
Absolute byte region of the source. |
:size? |
Int |
Number of bytes to take from the source cursor. |
:offset? |
Int |
Absolute byte offset in the destination. |
:clone? |
CloneMode |
How blocks should be shared between the source and destination. Defaults
to :AUTO:. |
fs_metadata() -> FsMetadata
Gets filesystem metadata for the filesystem backing the open file.
Example
lock[R] range func … -> R
Acquires a byte-range lock while func runs.
Parameters
| Name | Type | Description |
|---|---|---|
range |
Range[Int] |
Half-open byte range; .. is the whole
file. |
func |
((FileLock) -> R) |
Block receiving a
FileLock. |
:shared? |
Bool |
Acquire a shared rather than exclusive lock. |
Returns
The block's result.
The lock is exclusive unless shared is true. It is released before the
method returns, including when the block raises an error or is canceled.
Release runs with interruption masked and may wait indefinitely.
Locks are mandatory on Windows, where they prevent conflicting file access. On Unix they are advisory and affect only programs that cooperate through file locking.
Native blocking acquisition cannot be canceled. Canceling the strand may
leave a blocking worker waiting for a conflicting lock and delay shutdown.
Use try_lock for bounded or cancellable waiting.
Overlapping active lock ranges on the same file are unsupported, including identical shared ranges.
Finite zero-length ranges are invalid on Unix. On Windows they conflict
only with positive-length ranges that start before and end after their
offset. They do not conflict with another zero-length range or a range
starting at the same offset. The zero-length range 0..0 is invalid.
Example
metadata() -> Metadata
Gets metadata for the open file.
Example
open data.txt r do |file|
let meta = file.metadata()
echo "Size: $(meta.size)"
echo "Modified: $(meta.modified)"
read … -> (Str | Bin)
Reads data from the file.
Parameters
| Name | Type | Description |
|---|---|---|
size? |
Int |
Number of bytes to read. Without it, reads to the end of the file. |
:offset? |
Int |
Byte offset to read from. Without it, reads at the cursor and advances it. |
size
size bytes are read however many transfers that takes; a shorter result
means the end of the file was reached, and reading entirely past the end
gives an empty result rather than an error.
:offset
A positional read leaves the cursor where it was, so it can be used alongside streaming reads on the same handle, and several regions of a file can be read without seeking between them.
Because a positional read touches nothing shared, any number of them may be in flight on one handle at once — several strands can read different regions of the same open file concurrently. Streaming reads still take the handle exclusively, since they move the cursor.
In text mode the bytes read must be complete UTF-8. There is no cursor for a positional read to carry a split character forward on, so unlike a streaming read it cannot hold a partial character back for next time.
Returns
A Str in text mode, or a Bin in binary mode.
Example
# Read entire file
open input.txt r do |file|
let content = file.read()
echo "File contents: $content"
# Read a specific number of bytes
open data.bin rb do |file|
let header = file.read 4
let rest = file.read()
# Read a record without moving the cursor
open data.bin rb do |file|
let record = file.read 64 offset: (index * 64)
remove_xattr name …
Removes an extended attribute.
Parameters
| Name | Type | Description |
|---|---|---|
name |
(Str | XattrEntry) |
Attribute name
or entry from xattrs. |
:namespace? |
XattrNamespace |
Namespace to update. |
Example
sec_desc … -> security.windows.SecDesc
Gets selected parts of the Windows security descriptor through this file's existing handle.
The operation raises a permission error if the file was opened without the
necessary Windows access rights. Other platforms raise
sys.UnsupportedError.
Parameters
| Name | Type | Description |
|---|---|---|
:owner? |
Bool |
Load the owner SID. Defaults to true. |
:group? |
Bool |
Load the primary group SID. Defaults to
true. |
:dacl? |
Bool |
Load the discretionary ACL. Defaults to
true. |
:sacl? |
Bool |
Load the system ACL. Defaults to false. |
seek … -> Int
Moves the file cursor.
Buffered unread data is discarded before the seek so subsequent reads use the new cursor position.
Parameters
| Name | Type | Description |
|---|---|---|
offset? |
Int |
Byte offset relative to the current position. |
:start? |
Int |
Absolute byte offset from the start of the file. |
:end? |
Int |
Byte offset relative to the end of the file. |
Returns
The new absolute byte position.
Example
open data.bin rb do |file|
file.seek start: 10 # absolute
file.seek 10 # relative to the cursor
file.seek (0 - 4) # backwards
file.seek end: (0 - 1) # relative to the end
set_acl acl …
Sets or removes an ACL on the open file.
A built ACL supplies its format and must match an explicit kind:. An
untyped sequence of declarative ACE dictionaries requires kind:. With
nil, the omitted kind remains POSIX.
Parameters
| Name | Type | Description |
|---|---|---|
acl |
(security.AclSpec | nil) |
ACL or declarative ACE sequence. |
:kind? |
(:POSIX: | :NFS4: | :MACOS:) |
Required for an untyped ACL specification. |
:default? |
Bool |
Update the directory's inheritable default ACL. |
set_size size
Truncates the file to the given byte length.
If the file has buffered unread data, the logical cursor position is preserved after truncation.
Parameters
| Name | Type | Description |
|---|---|---|
size |
Int |
New file length in bytes. |
Example
set_xattr name value …
Sets an extended attribute value.
On Windows, empty values are rejected. NTFS deletes the attribute instead of storing an empty value.
Parameters
| Name | Type | Description |
|---|---|---|
name |
(Str | XattrEntry) |
Attribute name
or entry from xattrs. |
value |
(Str | Bin) |
Attribute bytes; strings use UTF-8. |
:namespace? |
XattrNamespace |
Namespace to update. |
Example
streams() -> Iter[fs.windows.StreamEntry]
Lists alternate data streams for this file.
Windows only.
Example
sync …
Flushes the file to durable storage, returning once the device reports it committed.
Parameters
| Name | Type | Description |
|---|---|---|
:data? |
Bool |
Flush data only, skipping unneeded metadata.
See fs.sync for what this selects and what a flush
does and does not guarantee. |
Example
tell() -> Int
Returns the current cursor position in bytes.
Example
try_lock[R] range func … -> R
Attempts to acquire a byte-range lock without waiting.
Parameters
| Name | Type | Description |
|---|---|---|
range |
Range[Int] |
Half-open byte range; .. is the whole
file. |
func |
((FileLock) -> R) |
Block receiving a
FileLock. |
:shared? |
Bool |
Acquire a shared rather than exclusive lock. |
Returns
The block's result.
The block always runs. lock.held is false when
another handle holds a conflicting lock. Other acquisition failures raise
errors.
Example
update_sec_desc ...options …
Applies the components selected by a security descriptor's mask through
this file's existing handle.
The operation raises a permission error if the file was opened without the
necessary Windows access rights. Windows may normalize the resulting
descriptor. Other platforms raise
sys.UnsupportedError.
Parameters
| Name | Type | Description |
|---|---|---|
desc? |
security.windows.SecDescSpec |
Descriptor to apply. |
...options |
Components, as sec_desc takes them, instead
of or alongside desc. |
write data … -> Int
Writes data to the file.
All of data is written, however many transfers that takes.
Parameters
| Name | Type | Description |
|---|---|---|
data |
(Str | Bin) |
Data to write. Strings are written as UTF-8 text. |
:offset? |
Int |
Byte offset to write at. Without it, writes at the cursor and advances it. |
:offset
A positional write leaves the cursor where it was, so it can be used alongside streaming writes on the same handle, and several regions of a file can be written without seeking between them. Writing past the end extends the file, zero-filling the gap.
As with read, any number of positional writes may be
in flight on one handle at once.
Returns
The number of bytes written.
Errors
| Exception | Condition |
|---|---|
StateError |
offset: on a file opened for appending |
An append handle writes at the end of the file no matter what offset the platform is given, so an explicit one cannot be honored rather than merely being unimplemented.
Example
open output.txt w do |file|
let bytes_written = file.write "Hello, World!"
echo "Wrote $bytes_written bytes"
file.write b"Hello"
# Patch a record in place without disturbing the cursor
open data.bin r+b do |file|
file.write $record offset: (index * 64)
xattr name … -> Bin
Gets an extended attribute value.
Parameters
| Name | Type | Description |
|---|---|---|
name |
(Str | XattrEntry) |
Attribute name
or entry from xattrs. |
:namespace? |
XattrNamespace |
Namespace to query. |
Example
xattrs … -> Iter[XattrEntry]
Lists extended attributes for this file.
On Windows, this uses NTFS extended attributes. Returned names may differ in case from the requested name.
Parameters
| Name | Type | Description |
|---|---|---|
:namespace? |
(XattrNamespace | :ANY:) |
Namespace to query; :ANY: lists all namespaces. |