Class: EM::File

Inherits:
Object
  • Object
show all
Defined in:
lib/em-files.rb

Overview

Sequenced file reader and writer.

Constant Summary collapse

RWSIZE =

Holds the default size of block operated during one tick.

65536

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filepath, mode = "r", rwsize = self.class::RWSIZE) ⇒ File

Constructor. If IO object is given instead of filepath, uses it as native one and mode argument is ignored.

Parameters:

  • filepath (String, IO, StringIO)

    path to file or IO object

  • mode (String) (defaults to: "r")

    file access mode (see equivalent Ruby method)

  • rwsize (Integer) (defaults to: self.class::RWSIZE)

    size of block operated during one tick



135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/em-files.rb', line 135

def initialize(filepath, mode = "r", rwsize = self.class::RWSIZE)
    @mode = mode
    @rw_len = rwsize
    
    rwsize = self::RWSIZE if rwsize.nil?
    
    # If filepath is directly IO, uses it
    if filepath.kind_of_any? [StringIO, IO]
        @native = filepath
    else
        @native = ::File::open(filepath, mode)
    end
    
end

Instance Attribute Details

#modeString (readonly)

Holds mode of the object.

Returns:

  • (String)


123
124
125
# File 'lib/em-files.rb', line 123

def mode
  @mode
end

#nativeIO

Holds file object.

Returns:

  • (IO)


107
108
109
# File 'lib/em-files.rb', line 107

def native
  @native
end

#rw_lenInteger

Indicates block size for operate with in one tick.

Returns:

  • (Integer)


115
116
117
# File 'lib/em-files.rb', line 115

def rw_len
  @rw_len
end

Class Method Details

.open(filepath, mode = "r", rwsize = self::RWSIZE, &block) ⇒ File

Opens the file.

In opposite to appropriate Ruby method, “block syntax” is only syntactic sugar, file isn’t closed after return from block because processing is asynchronous so it doesn’t know when is convenient to close the file.

Parameters:

  • filepath (String, IO, StringIO)

    path to file or IO object

  • mode (String) (defaults to: "r")

    file access mode (see equivalent Ruby method)

  • rwsize (Integer) (defaults to: self::RWSIZE)

    size of block operated during one tick

  • block (Proc)

    syntactic sugar for wrapping File access object

Returns:

  • (File)

    file access object



42
43
44
45
46
47
48
49
50
51
# File 'lib/em-files.rb', line 42

def self.open(filepath, mode = "r", rwsize = self::RWSIZE, &block)   # 64 kilobytes
    rwsize = self::RWSIZE if rwsize.nil?
    
    file = self::new(filepath, mode, rwsize)
    if not block.nil?
        block.call(file)
    end
    
    return file
end

.read(filepath, rwsize = self::RWSIZE, filter = nil, &block) ⇒ Object



66
67
68
69
70
71
72
73
74
# File 'lib/em-files.rb', line 66

def self.read(filepath, rwsize = self::RWSIZE, filter = nil, &block)
    rwsize = self::RWSIZE if rwsize.nil?
    self::open(filepath, "rb", rwsize) do |io|
        io.read(nil, filter) do |out|
            io.close()
            block.call(out)
        end
    end
end

.write(filepath, data = "", rwsize = self::RWSIZE, filter = nil, &block) ⇒ Object

Writes data to file and closes it. Writes them in binary mode. If IO object is given instead of filepath, uses it as native one and mode argument is ignored.

Parameters:

  • filepath (String, IO, StringIO)

    path to file or IO object

  • data (String) (defaults to: "")

    data for write

  • rwsize (Integer) (defaults to: self::RWSIZE)

    size of block operated during one tick

  • filter (Proc) (defaults to: nil)

    filter which for preprocessing each written chunk

  • block (Proc)

    block called when writing is finished with written bytes size count as parameter



90
91
92
93
94
95
96
97
98
# File 'lib/em-files.rb', line 90

def self.write(filepath, data = "", rwsize = self::RWSIZE, filter = nil, &block)
    rwsize = self::RWSIZE if rwsize.nil?
    self::open(filepath, "wb", rwsize) do |io|
        io.write(data, filter) do |length|
            io.close()
            block.call(length)
        end
    end
end

Instance Method Details

#closeObject

Closes the file.



287
288
289
# File 'lib/em-files.rb', line 287

def close
    @native.close
end

#read(length, &block) ⇒ Object #read(&block) ⇒ Object

Reads data from file.

It will reopen the file if EBADF: Bad file descriptor of File class IO object will occur.

Overloads:

  • #read(length, &block) ⇒ Object

    Reads specified amount of data from file.

    Parameters:

    • length (Integer)

      length for read from file

    • filter (Proc)

      filter which for postprocessing each read chunk

    • block (Proc)

      callback for returning the result

  • #read(&block) ⇒ Object

    Reads whole content of file.

    Parameters:

    • filter (Proc)

      filter which for processing each block

    • block (Proc)

      callback for returning the result



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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/em-files.rb', line 168

def read(length = nil, filter = nil, &block)
    buffer = ""
    pos = 0
    
    # Arguments
    if length.kind_of? Proc
        filter = length
    end
    
    
    worker = Proc::new do
    
        # Sets length for read
        if not length.nil?
            rlen = length - buffer.length
            if rlen > @rw_len
                rlen = @rw_len
            end
        else
            rlen = @rw_len
        end
        
        # Reads
        begin
            chunk = @native.read(rlen)
            if not filter.nil?
                chunk = filter.call(chunk)
            end
            buffer << chunk
        rescue Errno::EBADF
            if @native.kind_of? ::File
                self.reopen!
                @native.seek(pos)
                redo
            else
                raise
            end
        end
        
        pos = @native.pos
        
        # Returns or continues work
        if @native.eof? or (buffer.length == length)
            if not block.nil?
                block.call(buffer)              # returns result
            end
        else
            EM::next_tick { worker.call() }     # continues work
        end
        
    end
    
    worker.call()
end

#reopen!Object

Reopens the file with the original mode.



227
228
229
# File 'lib/em-files.rb', line 227

def reopen!
    @native = ::File.open(@native.path, @mode)
end

#write(data, filter = nil, &block) ⇒ Object

Writes data to file.

It will reopen the file if EBADF: Bad file descriptor of File class IO object will occur.

Parameters:

  • data (String)

    data for write

  • filter (Proc) (defaults to: nil)

    filter which for preprocessing each written chunk

  • block (Proc)

    callback called when finish and for giving back the length of written data



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/em-files.rb', line 244

def write(data, filter = nil, &block)
    written = 0
    pos = 0
    
    worker = Proc::new do
    
        # Writes
        begin
            chunk = data[written...(written + @rw_len)]
            if not filter.nil?
                chunk = filter.call(chunk)
            end
            written += @native.write(chunk)
        rescue Errno::EBADF
            if @native.kind_of? File
                self.reopen!
                @native.seek(pos)
                redo
            else
                raise
            end
        end
    
        pos = @native.pos
        
        # Returns or continues work
        if written >= data.bytesize
            if not block.nil?
                block.call(written)             # returns result
            end
        else
            EM::next_tick { worker.call() }     # continues work
        end
        
    end
    
    worker.call()
end