Skip to content

File

File objects are returned by open and provide methods for file operations. All operations on closed files raise a runtime error.

Inherits

Methods

write data

Writes data to the file.

Parameters

Name Type Description
data Str|Bin Data to write. Strings are written as UTF-8 text.

Returns

Int (number of bytes written)

Example

open output.txt w do |file|
  let bytes_written = file.write "Hello, World!"
  echo "Wrote $bytes_written bytes"

  # Write binary data
  let binary = b"Hello"
  file.write binary

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

open data.bin r+ do |file|
  file.set_size 8

lock range :shared? func

Acquires a byte-range lock while func runs.

Parameters:

Name Type Description
range Range Half-open byte range; .. is total
shared Bool? Acquire a shared lock
func Func Block receiving a FileLock

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 with async retry 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.

file.lock (0..128) do |lock|
  update_header()

try_lock range :shared? func

Attempts to acquire a byte-range lock without waiting.

Parameters:

Name Type Description
range Range Half-open byte range; .. is total
shared Bool? Acquire a shared lock
func Func Block receiving a FileLock

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.

file.try_lock (..) do |lock|
  if lock.held
    update_index()

read :size?

Reads data from the file.

Parameters

Name Type Description
size Int Number of bytes to read. If nil, reads entire file.

Returns

Str in text mode, binary blob in binary mode

Example

# Read entire file
open input.txt r do |file|
  let content = file.read()
  echo "File contents: $content"

# Read specific number of bytes
open data.bin rb do |file|
  let header = file.read 4
  let rest = file.read()

metadata()

Gets file metadata.

Returns

Metadata

Fields:

Field Type Description
len Int File size in bytes
type Sym File type: :FILE:, :DIR:, :SYMLINK:, :FIFO:, :CHAR_DEVICE:, :BLOCK_DEVICE:, :SOCKET:, or :UNKNOWN:

Optional timestamps (platform-dependent):

Field Type Description
modified DateTime Last modification time
accessed DateTime Last access time
created DateTime Creation/change time

Unix-only (these fields do not exist on Windows):

Field Type Description
mode Int File permissions and type (stat mode)
dev Int Device ID
ino Int Inode number
nlink Int Number of hard links
uid Int User ID of owner
gid Int Group ID of owner
rdev Int Device ID (if special file)
blksize Int Preferred block size for I/O
blocks Int Number of 512-byte blocks allocated

Windows-only (these fields do not exist on Unix):

Field Type Description
win_attrs Int Raw Windows file attribute bitmask

Example

open data.txt r do |file|
  let meta = file.metadata()
  echo "Size: $(meta.size)"
  echo "Type: $(meta.type)"
  echo "Modified: $(meta.modified)"
  echo "Modified seconds: $(meta.modified.unix_secs)"

  if (sys.os_info().family != :WINDOWS:)
    echo "Mode: $(meta.mode)"
    echo "Owner: UID=$(meta.uid), GID=$(meta.gid)"
  else
    echo "Attributes: $(meta.win_attrs)"

fs_metadata()

Gets filesystem metadata for the filesystem backing this open file.

Returns

FsMetadata

Example

open data.txt r do |file|
  let meta = file.fs_metadata()
  echo "Capacity: $(meta.capacity)"
  echo "Available: $(meta.available)"

sec_desc :owner = true :group = true :dacl = true :sacl = false

Gets selected parts of the Windows security descriptor through this file's existing handle.

Parameters:

Name Type Description
owner Bool Load the owner SID
group Bool Load the primary group SID
dacl Bool Load the discretionary ACL
sacl Bool Load the system ACL

Returns: security.windows.SecDesc

The operation raises a permission error if the file was opened without the necessary Windows access rights. Other platforms raise UnsupportedError.

set_sec_desc desc

Applies the components selected by a security descriptor's mask through this file's existing handle.

Parameters:

Name Type Description
desc security.windows.SecDesc Security descriptor to apply

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 UnsupportedError.

acl :default?

Gets the POSIX.1e ACL stored on the open file.

Parameters:

Name Type Description
default Bool? Query the directory's inheritable default ACL

Returns: security.unix.Acl, or nil

set_acl acl :default?

Sets or removes a POSIX.1e ACL on the open file.

Parameters:

Name Type Description
acl security.unix.Acl|nil ACL to set, or nil to remove it
default Bool? Update the directory's inheritable default ACL

xattrs :namespace?

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 Str|Sym? Namespace to query; :USER: and :SYSTEM: name well-known namespaces, and :ANY: lists all namespaces

Returns

iterator of XattrEntry

open data.txt r do |file|
  for attr = file.xattrs()
    echo $attr.name

streams

Lists alternate data streams for this file.

This is only supported on Windows.

Returns

iterator of StreamEntry

let path = Path data.txt
open $path r do |file|
  for stream = file.streams()
    echo "$(stream.name) $(stream.type)"
    echo (path / stream)

xattr name :namespace?

Gets an extended attribute value.

Parameters

Name Type Description
name Str|XattrEntry Attribute name or entry from xattrs
namespace Str|Sym? Namespace to query

Returns

Bin

open data.txt r do |file|
  let value = file.xattr "comment"

set_xattr name value :namespace?

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 Str|Sym? Namespace to update
open data.txt r+ do |file|
  file.set_xattr "comment" "ready"

remove_xattr name :namespace?

Removes an extended attribute.

Parameters

Name Type Description
name Str|XattrEntry Attribute name or entry from xattrs
namespace Str|Sym? Namespace to update
open data.txt r+ do |file|
  file.remove_xattr "comment"

seek offset

Moves the file cursor by a relative byte offset.

Buffered unread data is discarded before the seek so subsequent reads use the new cursor position.

Parameters

Name Type Description
offset Int Relative byte offset from current

Returns

Int - New absolute byte position

Example

open data.bin rb do |file|
  file.seek 10
  file.seek (0 - 4)

seek start: ofs

Moves the file cursor to an absolute byte offset from the start of the file.

Buffered unread data is discarded before the seek so subsequent reads use the new cursor position.

Parameters

Name Type Description
ofs Int Absolute byte offset from file start

Returns

Int - New absolute byte position

Example

open data.bin rb do |file|
  file.seek start: 10
  let pos = file.tell()

seek end: ofs

Moves the file cursor to a byte offset relative to the end of the file.

Buffered unread data is discarded before the seek so subsequent reads use the new cursor position.

Parameters

Name Type Description
ofs Int Byte offset relative to file end

Returns

Int - New absolute byte position

Example

open data.bin rb do |file|
  file.seek end: (0 - 1)

tell()

Returns the current file cursor position in bytes.

Returns

Int

Example

open data.txt r do |file|
  assert_eq (file.tell()) 0
  file.read 5
  assert_eq (file.tell()) 5

close()

Explicitly closes the file. Required if you didn't use the func parameter to open().

Example

let file = open data.txt r
let data = file.read()
file.close()

Iterator and Sink Protocols

Files implement the iterator and sink protocols, allowing them to be used with for loops, .next(), .put(), and strand.redirect.

input/output

Returns the file as its own iterator and sink.

Returns

The file object itself

next

Fetches the next item from the file.

Text mode: Reads the next line (delimited by \n), stripping the line ending. Handles both \n and \r\n line endings.

Binary mode: Reads a chunk of data of arbitrary length.

put

Writes a value to the file.

Text mode:

  • If the value is binary data (Bin), writes it unmodified
  • Otherwise, converts to string and appends the line ending for the VFS target on which the file handle was opened

Binary mode: Writes bytes directly.