diff --git a/extensions/mongo/Query.php b/extensions/mongo/Query.php
index 8c46479..5f313f4 100644
--- a/extensions/mongo/Query.php
+++ b/extensions/mongo/Query.php
@@ -129,33 +129,13 @@ class Query extends Component implements QueryInterface
 	 * @throws Exception on failure.
 	 * @return array|boolean result.
 	 */
-	protected function fetchRows(\MongoCursor $cursor, $all = true, $indexBy = null)
+	protected function fetchRows($cursor, $all = true, $indexBy = null)
 	{
 		$token = 'Querying: ' . Json::encode($cursor->info());
 		Yii::info($token, __METHOD__);
 		try {
 			Yii::beginProfile($token, __METHOD__);
-			$result = [];
-			if ($all) {
-				foreach ($cursor as $row) {
-					if ($indexBy !== null) {
-						if (is_string($indexBy)) {
-							$key = $row[$indexBy];
-						} else {
-							$key = call_user_func($indexBy, $row);
-						}
-						$result[$key] = $row;
-					} else {
-						$result[] = $row;
-					}
-				}
-			} else {
-				if ($cursor->hasNext()) {
-					$result = $cursor->getNext();
-				} else {
-					$result = false;
-				}
-			}
+			$result = $this->fetchRowsInternal($cursor, $all, $indexBy);
 			Yii::endProfile($token, __METHOD__);
 			return $result;
 		} catch (\Exception $e) {
@@ -165,6 +145,39 @@ class Query extends Component implements QueryInterface
 	}
 
 	/**
+	 * @param \MongoCursor $cursor Mongo cursor instance to fetch data from.
+	 * @param boolean $all whether to fetch all rows or only first one.
+	 * @param string|callable $indexBy value to index by.
+	 * @return array|boolean result.
+	 * @see Query::fetchRows()
+	 */
+	protected function fetchRowsInternal($cursor, $all, $indexBy)
+	{
+		$result = [];
+		if ($all) {
+			foreach ($cursor as $row) {
+				if ($indexBy !== null) {
+					if (is_string($indexBy)) {
+						$key = $row[$indexBy];
+					} else {
+						$key = call_user_func($indexBy, $row);
+					}
+					$result[$key] = $row;
+				} else {
+					$result[] = $row;
+				}
+			}
+		} else {
+			if ($cursor->hasNext()) {
+				$result = $cursor->getNext();
+			} else {
+				$result = false;
+			}
+		}
+		return $result;
+	}
+
+	/**
 	 * Executes the query and returns all results as an array.
 	 * @param Connection $db the Mongo connection used to execute the query.
 	 * If this parameter is not given, the `mongo` application component will be used.
diff --git a/extensions/mongo/file/ActiveRecord.php b/extensions/mongo/file/ActiveRecord.php
index bbdf10d..fd9367b 100644
--- a/extensions/mongo/file/ActiveRecord.php
+++ b/extensions/mongo/file/ActiveRecord.php
@@ -205,7 +205,7 @@ class ActiveRecord extends \yii\mongo\ActiveRecord
 	/**
 	 * Returns the associated file content.
 	 * @return null|string file content.
-	 * @throws \yii\base\InvalidParamException on invalid file value.
+	 * @throws \yii\base\InvalidParamException on invalid file attribute value.
 	 */
 	public function getFileContent()
 	{
@@ -227,6 +227,67 @@ class ActiveRecord extends \yii\mongo\ActiveRecord
 		} elseif (is_string($file)) {
 			if (file_exists($file)) {
 				return file_get_contents($file);
+			} else {
+				throw new InvalidParamException("File '{$file}' does not exist.");
+			}
+		} else {
+			throw new InvalidParamException('Unsupported type of "file" attribute.');
+		}
+	}
+
+	/**
+	 * Writes the the internal file content into the given filename.
+	 * @param string $filename full filename to be written.
+	 * @return boolean whether the operation was successful.
+	 * @throws \yii\base\InvalidParamException on invalid file attribute value.
+	 */
+	public function writeFile($filename)
+	{
+		$file = $this->getAttribute('file');
+		if (empty($file) && !$this->getIsNewRecord()) {
+			$file = $this->refreshFile();
+		}
+		if (empty($file)) {
+			throw new InvalidParamException('There is no file associated with this object.');
+		} elseif ($file instanceof \MongoGridFSFile) {
+			return ($file->write($filename) == $file->getSize());
+		} elseif ($file instanceof UploadedFile) {
+			return copy($file->tempName, $filename);
+		} elseif (is_string($file)) {
+			if (file_exists($file)) {
+				return copy($file, $filename);
+			} else {
+				throw new InvalidParamException("File '{$file}' does not exist.");
+			}
+		} else {
+			throw new InvalidParamException('Unsupported type of "file" attribute.');
+		}
+	}
+
+	/**
+	 * This method returns a stream resource that can be used with all file functions in PHP,
+	 * which deal with reading files. The contents of the file are pulled out of MongoDB on the fly,
+	 * so that the whole file does not have to be loaded into memory first.
+	 * @return resource file stream resource.
+	 * @throws \yii\base\InvalidParamException on invalid file attribute value.
+	 */
+	public function getFileResource()
+	{
+		$file = $this->getAttribute('file');
+		if (empty($file) && !$this->getIsNewRecord()) {
+			$file = $this->refreshFile();
+		}
+		if (empty($file)) {
+			throw new InvalidParamException('There is no file associated with this object.');
+		} elseif ($file instanceof \MongoGridFSFile) {
+			return $file->getResource();
+		} elseif ($file instanceof UploadedFile) {
+			return fopen($file->tempName, 'r');
+		} elseif (is_string($file)) {
+			if (file_exists($file)) {
+				return fopen($file, 'r');
+			} else {
+				throw new InvalidParamException("File '{$file}' does not exist.");
 			}
 		} else {
 			throw new InvalidParamException('Unsupported type of "file" attribute.');
diff --git a/extensions/mongo/file/Query.php b/extensions/mongo/file/Query.php
index b22b64f..4c1e5ff 100644
--- a/extensions/mongo/file/Query.php
+++ b/extensions/mongo/file/Query.php
@@ -33,50 +33,39 @@ class Query extends \yii\mongo\Query
 	}
 
 	/**
-	 * Fetches rows from the given Mongo cursor.
-	 * @param \MongoCursor $cursor Mongo cursor instance to fetch data from.
+	 * @param \MongoGridFSCursor $cursor Mongo cursor instance to fetch data from.
 	 * @param boolean $all whether to fetch all rows or only first one.
-	 * @param string|callable $indexBy the column name or PHP callback,
-	 * by which the query results should be indexed by.
-	 * @throws Exception on failure.
+	 * @param string|callable $indexBy value to index by.
 	 * @return array|boolean result.
+	 * @see Query::fetchRows()
 	 */
-	protected function fetchRows(\MongoCursor $cursor, $all = true, $indexBy = null)
+	protected function fetchRowsInternal($cursor, $all, $indexBy)
 	{
-		$token = 'Querying: ' . Json::encode($cursor->info());
-		Yii::info($token, __METHOD__);
-		try {
-			Yii::beginProfile($token, __METHOD__);
-			$result = [];
-			if ($all) {
-				foreach ($cursor as $file) {
-					$row = $file->file;
-					$row['file'] = $file;
-					if ($indexBy !== null) {
-						if (is_string($indexBy)) {
-							$key = $row[$indexBy];
-						} else {
-							$key = call_user_func($indexBy, $row);
-						}
-						$result[$key] = $row;
+		$result = [];
+		if ($all) {
+			foreach ($cursor as $file) {
+				$row = $file->file;
+				$row['file'] = $file;
+				if ($indexBy !== null) {
+					if (is_string($indexBy)) {
+						$key = $row[$indexBy];
 					} else {
-						$result[] = $row;
+						$key = call_user_func($indexBy, $row);
 					}
-				}
-			} else {
-				if ($cursor->hasNext()) {
-					$file = $cursor->getNext();
-					$result = $file->file;
-					$result['file'] = $file;
+					$result[$key] = $row;
 				} else {
-					$result = false;
+					$result[] = $row;
 				}
 			}
-			Yii::endProfile($token, __METHOD__);
-			return $result;
-		} catch (\Exception $e) {
-			Yii::endProfile($token, __METHOD__);
-			throw new Exception($e->getMessage(), (int)$e->getCode(), $e);
+		} else {
+			if ($cursor->hasNext()) {
+				$file = $cursor->getNext();
+				$result = $file->file;
+				$result['file'] = $file;
+			} else {
+				$result = false;
+			}
 		}
+		return $result;
 	}
 }
\ No newline at end of file
diff --git a/tests/unit/extensions/mongo/file/ActiveRecordTest.php b/tests/unit/extensions/mongo/file/ActiveRecordTest.php
index 93c2cc2..93fb552 100644
--- a/tests/unit/extensions/mongo/file/ActiveRecordTest.php
+++ b/tests/unit/extensions/mongo/file/ActiveRecordTest.php
@@ -2,6 +2,8 @@
 
 namespace yiiunit\extensions\mongo\file;
 
+use Yii;
+use yii\helpers\FileHelper;
 use yiiunit\extensions\mongo\MongoTestCase;
 use yii\mongo\file\ActiveQuery;
 use yiiunit\data\ar\mongo\file\ActiveRecord;
@@ -22,15 +24,31 @@ class ActiveRecordTest extends MongoTestCase
 		parent::setUp();
 		ActiveRecord::$db = $this->getConnection();
 		$this->setUpTestRows();
+		$filePath = $this->getTestFilePath();
+		if (!file_exists($filePath)) {
+			FileHelper::createDirectory($filePath);
+		}
 	}
 
 	protected function tearDown()
 	{
+		$filePath = $this->getTestFilePath();
+		if (file_exists($filePath)) {
+			FileHelper::removeDirectory($filePath);
+		}
 		$this->dropFileCollection(CustomerFile::collectionName());
 		parent::tearDown();
 	}
 
 	/**
+	 * @return string test file path.
+	 */
+	protected function getTestFilePath()
+	{
+		return Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . basename(get_class($this)) . '_' . getmypid();
+	}
+
+	/**
 	 * Sets up test rows.
 	 */
 	protected function setUpTestRows()
@@ -256,4 +274,50 @@ class ActiveRecordTest extends MongoTestCase
 		$this->assertEquals($record->status, $record2->status);
 		$this->assertEquals($updateFileContent, $record2->getFileContent());
 	}
+
+	/**
+	 * @depends testInsertFileContent
+	 */
+	public function testWriteFile()
+	{
+		$record = new CustomerFile;
+		$record->tag = 'new new';
+		$record->status = 7;
+		$newFileContent = 'Test new file content';
+		$record->setAttribute('newFileContent', $newFileContent);
+		$record->save();
+
+		$outputFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . 'out.txt';
+		$this->assertTrue($record->writeFile($outputFileName));
+		$this->assertEquals($newFileContent, file_get_contents($outputFileName));
+
+		$record2 = CustomerFile::find($record->_id);
+		$outputFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . 'out_refreshed.txt';
+		$this->assertTrue($record2->writeFile($outputFileName));
+		$this->assertEquals($newFileContent, file_get_contents($outputFileName));
+	}
+
+	/**
+	 * @depends testInsertFileContent
+	 */
+	public function testGetFileResource()
+	{
+		$record = new CustomerFile;
+		$record->tag = 'new new';
+		$record->status = 7;
+		$newFileContent = 'Test new file content';
+		$record->setAttribute('newFileContent', $newFileContent);
+		$record->save();
+
+		$fileResource = $record->getFileResource();
+		$contents = stream_get_contents($fileResource);
+		fclose($fileResource);
+		$this->assertEquals($newFileContent, $contents);
+
+		$record2 = CustomerFile::find($record->_id);
+		$fileResource = $record2->getFileResource();
+		$contents = stream_get_contents($fileResource);
+		fclose($fileResource);
+		$this->assertEquals($newFileContent, $contents);
+	}
 }
\ No newline at end of file