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)

    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



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

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? IO
        @native = filepath
    else
        @native = ::File::open(filepath, mode)
    end
    
end

Instance Attribute Details

#modeString (readonly)

Holds mode of the object.

Returns:

  • (String)


121
122
123
# File 'lib/em-files.rb', line 121

def mode
  @mode
end

#nativeIO

Holds file object.

Returns:

  • (IO)


105
106
107
# File 'lib/em-files.rb', line 105

def native
  @native
end

#rw_lenInteger

Indicates block size for operate with in one tick.

Returns:

  • (Integer)


113
114
115
# File 'lib/em-files.rb', line 113

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)

    path to file

  • 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



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

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



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

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)

    path to file

  • 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



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

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.



285
286
287
# File 'lib/em-files.rb', line 285

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



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

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.



225
226
227
# File 'lib/em-files.rb', line 225

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



242
243
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
# File 'lib/em-files.rb', line 242

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