Class: Win32::NIO
- Inherits:
-
Object
- Object
- Win32::NIO
- Extended by:
- Windows::Functions, Windows::Macros
- Includes:
- Windows::Constants, Windows::Structs
- Defined in:
- lib/win32/nio.rb
Overview
The NIO class encapsulates the native IO methods for MS Windows.
Constant Summary collapse
- VERSION =
The version of the win32-nio library
'0.1.3'
Class Method Summary collapse
-
.read(name, length = nil, offset = 0, options = {}) ⇒ Object
This method is similar to Ruby’s IO.read method except that it uses native function calls.
-
.readlines(file, sep = "\r\n") ⇒ Object
Reads the entire file specified by portname as individual lines, and returns those lines in an array.
Methods included from Windows::Macros
Class Method Details
.read(name, length = nil, offset = 0, options = {}) ⇒ Object
This method is similar to Ruby’s IO.read method except that it uses native function calls.
Examples:
# Read everything Win32::NIO.read(file)
# Read the first 100 bytes Win32::NIO.read(file, 100)
# Read 50 bytes starting at offset 10 Win32::NIO.read(file, 50, 10)
Note that the options
that may be passed to this method are limited to :encoding, :mode and :event because we’re no longer using the open function internally. In the case of :mode the only thing that is checked for is the presence of the ‘b’ (binary) mode.
The :event option, if present, must be a Win32::Event object. – In practice the fact that I ignore open_args: is irrelevant since you would never want to open in anything other than GENERIC_READ. I suppose I could change this to as a way to pass flags to CreateFile.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/win32/nio.rb', line 47 def self.read(name, length=nil, offset=0, ={}) begin fname = name + "\0" fname.encode!('UTF-16LE') flags = FILE_FLAG_SEQUENTIAL_SCAN olap = Overlapped.new event = [:event] if event raise TypeError unless event.is_a?(Win32::Event) end olap[:Offset] = offset if offset > 0 || event flags |= FILE_FLAG_OVERLAPPED olap[:hEvent] = event.handle if event end handle = CreateFileW( fname, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, flags, 0 ) if handle == INVALID_HANDLE_VALUE raise SystemCallError.new("CreateFile", FFI.errno) end length ||= File.size(name) buf = 0.chr * length if block_given? callback = Proc.new{ |e,b,o| block.call } bool = ReadFileEx(handle, buf, buf.size, olap, callback) else bool = ReadFile(handle, buf, buf.size, nil, olap) end errno = FFI.errno SleepEx(1, true) # Must be in alertable wait state unless bool if errno == ERROR_IO_PENDING bytes = FFI::MemoryPointer.new(:ulong) unless GetOverlappedResult(handle, olap, bytes, true) raise SystemCallError.new("GetOverlappedResult", FFI.errno) end else raise SystemCallError.new("ReadFile", errno) end end result = buf.delete(0.chr) result.encode!([:encoding]) if [:encoding] if [:mode] && [:mode].include?('t') && ($/ != "\r\n") result.gsub!(/\r\n/, $/) end result ensure CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE end end |
.readlines(file, sep = "\r\n") ⇒ Object
Reads the entire file specified by portname as individual lines, and returns those lines in an array. Lines are separated by sep
. – The semantics are the same as the MRI version but the implementation is drastically different. We use a scattered IO read.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/win32/nio.rb', line 126 def self.readlines(file, sep = "\r\n") fname = file + "\0" fname.encode!('UTF-16LE') begin handle = CreateFileW( fname, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, 0 ) if handle == INVALID_HANDLE_VALUE raise SystemCallError.new("CreateFileW", FFI.errno) end sysinfo = SystemInfo.new GetSystemInfo(sysinfo) file_size = File.size(file) page_size = sysinfo[:dwPageSize] page_num = (file_size.to_f / page_size).ceil begin size = page_size * page_num base_address = VirtualAlloc(nil, size, MEM_COMMIT, PAGE_READWRITE) if base_address == 0 raise SystemCallError.new("VirtualAlloc", FFI.errno) end # Add 1 for null as per the docs array = FFI::MemoryPointer.new(FileSegmentElement, page_num + 1) for i in 0...page_num fse = FileSegmentElement.new(array[i]) fse[:Alignment] = base_address + page_size * i end overlapped = Overlapped.new bool = ReadFileScatter(handle, array, size, nil, overlapped) unless bool error = FFI.errno if error == ERROR_IO_PENDING SleepEx(1, true) while !HasOverlappedIoCompleted(overlapped) else raise SystemCallError.new("ReadFileScatter", error) end end string = array[0].read_pointer.read_string if sep == "" array = string.split(/(\r\n){2,}/) array.delete("\r\n") else array = string.split(sep) end array ensure VirtualFree(base_address, 0, MEM_RELEASE) end ensure CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE end end |