MFile
Memory mapped file
If no capacity is given the file is open in read only mode and
capacity is set to the current file size.
If the process crashes the file will be capacity large,
not size large, only on graceful close is the file truncated to its size.
The file does not expand further than initial capacity, unless manually expanded.
Constants
madvise(MADV_DONTNEED) over PMD_SIZE or more lets the kernel reclaim the
emptied page table, and that reclaim flushes the TLB at the wrong address on
Linux 7.0.0-rc1 through 7.1.8 (CVE-2026-74674). Whatever maps that address
next then faults in a loop. The check is >=, so one page under is the
largest safe call. Only DontNeed zaps PTEs; the other advices set VMA flags,
where chunking would needlessly split the VMA.
One PTE page table maps PAGE_SIZE / sizeof(pte_t) entries, 8 bytes each on 64-bit: 2 MiB with 4K pages, 512 MiB with 64K pages.
Constructors
Class methods
Instance methods
Bytes the file occupies on disk as of open. A segment a crash left at its capacity is sparse past its data, and reading the hole would only zero-fill page cache
The file will be truncated to its size unless readonly or deleted. A leased file (see #lease) is unmapped when the last lease is released instead. That unmap doesn't truncate, as the file may have been opened again by then, so a leased file is truncated right away. The flag is set before the lease count is read, and release_lease decrements before reading the flag, so at least one of them sees the other and unmaps (close_mapping is idempotent).
Returns true if this IO is closed.
IO defines returns false, but including types may override.
Flushes buffered data, if any.
IO defines this is a no-op method, but including types may override.
Block until the written pages are on disk. A file closed in the meantime still has its dirty pages in the page cache, so fsync it by path instead, unless it's deleted and nothing needs to be persisted.
Appends a String representation of this object which includes its class name, its object address and the values of all instance variables.
class Person
def initialize(@name : String, @age : Int32)
end
end
Person.new("John", 32).inspect # => #<Person:0x10fd31f20 @name="John", @age=32>
Keeps the mapping open until #release_lease, even if #close is called meanwhile. Must not be called after #close.
Returns the current position (in bytes) in this IO.
The IO class raises on this method, but some subclasses, notable
IO::FileDescriptor and IO::Memory implement it.
File.write("testfile", "hello")
file = File.new("testfile")
file.pos # => 0
file.gets(2) # => "he"
file.pos # => 2
Sets the current position (in bytes) in this IO.
The IO class raises on this method, but some subclasses, notable
IO::FileDescriptor and IO::Memory implement it.
File.write("testfile", "hello")
file = File.new("testfile")
file.pos = 3
file.gets_to_end # => "lo"
Reads at most slice.size bytes from this IO into slice.
Returns the number of bytes read, which is 0 if and only if there is no
more data to read (so checking for 0 is the way to detect end of file).
io = IO::Memory.new "hello"
slice = Bytes.new(4)
io.read(slice) # => 4
slice # => Bytes[104, 101, 108, 108]
io.read(slice) # => 1
slice # => Bytes[111, 101, 108, 108]
io.read(slice) # => 0
Reads a single byte from this IO. Returns nil if there is no more
data to read.
io = IO::Memory.new "a"
io.read_byte # => 97
io.read_byte # => nil
Resize the file, so that read operations can't happen beyond new_size
this does not change the actual file size on disk
and you can still write beyond new_size
Reads and discards exactly bytes_count bytes.
Raises IO::EOFError if there aren't at least bytes_count bytes.
io = IO::Memory.new "hello world"
io.skip(6)
io.gets # => "world"
io.skip(1) # raises IO::EOFError
Truncate the file to the given capacity (contracting only, no expansion) The truncated part is unmapped from memory