Question

Is there some PHP function or class that allows me to read a file like an array of characters?

For example:

$string = str_split('blabla');

$i = 0;

switch($string[$i]){

  case 'x':
    do_something();
    $i++;


  case 'y':
    if(isset($string[++$i]))
      do_something_else();
    else
      break;

   case 'z':
      // recursive call of this code etc..

}

I know that I can use $string = file_get_contents($file), but the problem is that I get a huge amount of memory used for a tiny 800K file (like 80MB).

So can I somehow "stream" the file in my code above with some kind of arrayaccess like class that automatically reads data from the file when I call isset() ? :)

Was it helpful?

Solution

You can use fseek and fgetc to jump around in a file and read single characters at a time.

// Leaves the file handle modified
function get_char($file, $char) {
   fseek($file, $char);
   return fgetc($file);
}

You mentioned you wanted array behavior specifically. You can build a class which implements ArrayAccess to support this.

This could be dangerous for several reasons:

  • You'll need to guard against $char inputs that request indices past the length of the file
  • The file handle will be constantly mutated (should be okay, as long as you're not using it elsewhere)
  • This could be inefficient (offset by caching past requests)

A slightly more efficient alternative would be to "lazily" read the file (i.e., read it in chunks rather than all at once). Here's some (untested) code:

class BufferedReader {
    // The size of a chunk in bytes
    const BUFFER_SIZE = 512;

    protected $file;
    protected $data;

    function __construct($fname) {
        $this->file = fopen($fname, 'r');
    }

    function read_buffer() {
        $this->data .= fread($this->file, self::BUFFER_SIZE);
    }

    function get_char($char) {
        while ( $char >= strlen($this->data) && !feof($this->file) ) {
            $this->read_buffer();
        }

        if ( $char >= strlen($this->data) ) {
            return FALSE;
        }

        return substr($this->data, $char, 1);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top