diff --git a/core/includes/file.inc b/core/includes/file.inc
index 6393000..e885054 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -5,6 +5,9 @@
  * API for handling file uploads and server file management.
  */
 
+use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Utility\Url;
+use Drupal\Core\Utility\File;
 use Drupal\Core\StreamWrapper\LocalStream;
 use Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage;
 
@@ -178,36 +181,21 @@ function file_stream_wrapper_get_class($scheme) {
 /**
  * Returns the scheme of a URI (e.g. a stream).
  *
- * @param string $uri
- *   A stream, referenced as "scheme://target".
- *
- * @return string|bool
- *   A string containing the name of the scheme, or FALSE if none. For example,
- *   the URI "public://example.txt" would return "public".
- *
  * @see file_uri_target()
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::uriScheme().
  */
 function file_uri_scheme($uri) {
-  $position = strpos($uri, '://');
-  return $position ? substr($uri, 0, $position) : FALSE;
+  return File::uriScheme($uri);
 }
 
 /**
  * Checks that the scheme of a stream URI is valid.
  *
- * Confirms that there is a registered stream handler for the provided scheme
- * and that it is callable. This is useful if you want to confirm a valid
- * scheme without creating a new instance of the registered handler.
- *
- * @param string $scheme
- *   A URI scheme, a stream is referenced as "scheme://target".
- *
- * @return bool
- *   Returns TRUE if the string is the name of a validated stream,
- *   or FALSE if the scheme does not have a registered handler.
+ * @deprecated Use \Drupal\Core\Utility\File::validScheme().
  */
 function file_stream_wrapper_valid_scheme($scheme) {
-  return $scheme && class_exists(file_stream_wrapper_get_class($scheme));
+  return File::validScheme($scheme);
 }
 
 
@@ -238,7 +226,7 @@ function file_uri_target($uri) {
  *   'public', 'private' or any other file scheme defined as the default.
  */
 function file_default_scheme() {
-  return config('system.file')->get('default_scheme');
+  return Drupal::config('system.file')->get('default_scheme');
 }
 
 /**
@@ -257,9 +245,9 @@ function file_default_scheme() {
  *   The normalized URI.
  */
 function file_stream_wrapper_uri_normalize($uri) {
-  $scheme = file_uri_scheme($uri);
+  $scheme = File::uriScheme($uri);
 
-  if (file_stream_wrapper_valid_scheme($scheme)) {
+  if (File::validScheme($scheme)) {
     $target = file_uri_target($uri);
 
     if ($target !== FALSE) {
@@ -325,11 +313,11 @@ function file_stream_wrapper_get_instance_by_scheme($scheme) {
  * - "shipped files", i.e. those outside of the files directory, which ship as
  *   part of Drupal core or contributed modules or themes.
  *
- * @param $uri
+ * @param string $uri
  *   The URI to a file for which we need an external URL, or the path to a
  *   shipped file.
  *
- * @return
+ * @return string
  *   A string containing a URL that may be used to access the file.
  *   If the provided string already contains a preceding 'http', 'https', or
  *   '/', nothing is done and the same string is returned. If a stream wrapper
@@ -340,9 +328,9 @@ function file_stream_wrapper_get_instance_by_scheme($scheme) {
 function file_create_url($uri) {
   // Allow the URI to be altered, e.g. to serve a file from a CDN or static
   // file server.
-  drupal_alter('file_url', $uri);
+  Drupal::moduleHandler()->alter('file_url', $uri);
 
-  $scheme = file_uri_scheme($uri);
+  $scheme = File::uriScheme($uri);
 
   if (!$scheme) {
     // Allow for:
@@ -352,13 +340,13 @@ function file_create_url($uri) {
     //   HTTP and to https://example.com/bar.jpg when viewing a HTTPS page)
     // Both types of relative URIs are characterized by a leading slash, hence
     // we can use a single check.
-    if (drupal_substr($uri, 0, 1) == '/') {
+    if (Unicode::substr($uri, 0, 1) == '/') {
       return $uri;
     }
     else {
       // If this is not a properly formatted stream, then it is a shipped file.
       // Therefore, return the urlencoded URI with the base URL prepended.
-      return $GLOBALS['base_url'] . '/' . drupal_encode_path($uri);
+      return $GLOBALS['base_url'] . '/' . Url::encodePath($uri);
     }
   }
   elseif ($scheme == 'http' || $scheme == 'https') {
@@ -383,20 +371,20 @@ function file_create_url($uri) {
  * Directories need to have execute permissions to be considered a directory by
  * FTP servers, etc.
  *
- * @param $directory
+ * @param string $directory
  *   A string reference containing the name of a directory path or URI. A
  *   trailing slash will be trimmed from a path.
- * @param $options
+ * @param int $options
  *   A bitmask to indicate if the directory should be created if it does
  *   not exist (FILE_CREATE_DIRECTORY) or made writable if it is read-only
  *   (FILE_MODIFY_PERMISSIONS).
  *
- * @return
+ * @return bool
  *   TRUE if the directory exists (or was created) and is writable. FALSE
  *   otherwise.
  */
 function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS) {
-  if (!file_stream_wrapper_valid_scheme(file_uri_scheme($directory))) {
+  if (!File::validScheme(File::uriScheme($directory))) {
     // Only trim if we're not dealing with a stream.
     $directory = rtrim($directory, '/\\');
   }
@@ -406,14 +394,14 @@ function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS)
     // Let mkdir() recursively create directories and use the default directory
     // permissions.
     if ($options & FILE_CREATE_DIRECTORY) {
-      return @drupal_mkdir($directory, NULL, TRUE);
+      return @File::mkdir($directory, NULL, TRUE);
     }
     return FALSE;
   }
   // The directory exists, so check to see if it is writable.
   $writable = is_writable($directory);
   if (!$writable && ($options & FILE_MODIFY_PERMISSIONS)) {
-    return drupal_chmod($directory);
+    return File::chmod($directory);
   }
 
   return $writable;
@@ -424,7 +412,7 @@ function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS)
  */
 function file_ensure_htaccess() {
   file_save_htaccess('public://', FALSE);
-  $private_path = config('system.file')->get('path.private');
+  $private_path = Drupal::config('system.file')->get('path.private');
   if (!empty($private_path)) {
     file_save_htaccess('private://', TRUE);
   }
@@ -443,7 +431,7 @@ function file_ensure_htaccess() {
  *   The default is TRUE which indicates a private and protected directory.
  */
 function file_save_htaccess($directory, $private = TRUE) {
-  if (file_uri_scheme($directory)) {
+  if (File::uriScheme($directory)) {
     $directory = file_stream_wrapper_uri_normalize($directory);
   }
   else {
@@ -467,7 +455,7 @@ function file_save_htaccess($directory, $private = TRUE) {
 
   // Write the .htaccess file.
   if (file_put_contents($htaccess_path, $htaccess_lines)) {
-    drupal_chmod($htaccess_path, 0444);
+    File::chmod($htaccess_path, 0444);
   }
   else {
     $variables = array('%directory' => $directory, '!htaccess' => '<br />' . nl2br(check_plain($htaccess_lines)));
@@ -482,16 +470,16 @@ function file_save_htaccess($directory, $private = TRUE) {
  * 'public', 'private', 'temporary', or an extension provided with
  * hook_stream_wrappers().
  *
- * @param $uri
+ * @param string $uri
  *   The URI to be tested.
  *
- * @return
+ * @return bool
  *   TRUE if the URI is allowed.
  */
 function file_valid_uri($uri) {
   // Assert that the URI has an allowed scheme. Barepaths are not allowed.
-  $uri_scheme = file_uri_scheme($uri);
-  if (!file_stream_wrapper_valid_scheme($uri_scheme)) {
+  $uri_scheme = File::uriScheme($uri);
+  if (!File::validScheme($uri_scheme)) {
     return FALSE;
   }
   return TRUE;
@@ -512,20 +500,20 @@ function file_valid_uri($uri) {
  *   support streams if safe_mode or open_basedir are enabled. See
  *   https://bugs.php.net/bug.php?id=60456
  *
- * @param $source
+ * @param string $source
  *   A string specifying the filepath or URI of the source file.
- * @param $destination
+ * @param string $destination
  *   A URI containing the destination that $source should be copied to. The
  *   URI may be a bare filepath (without a scheme). If this value is omitted,
  *   Drupal's default files scheme will be used, usually "public://".
- * @param $replace
+ * @param int $replace
  *   Replace behavior when the destination file already exists:
  *   - FILE_EXISTS_REPLACE - Replace the existing file.
  *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
  *       unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  *
- * @return
+ * @return string|bool
  *   The path to the new file, or FALSE in the event of an error.
  *
  * @see file_copy()
@@ -537,7 +525,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
   if (!file_exists($source)) {
     // @todo Replace drupal_set_message() calls with exceptions instead.
     drupal_set_message(t('The specified file %file could not be copied because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $original_source)), 'error');
-    if (($realpath = drupal_realpath($original_source)) !== FALSE) {
+    if (($realpath = File::realpath($original_source)) !== FALSE) {
       watchdog('file', 'File %file (%realpath) could not be copied because it does not exist.', array('%file' => $original_source, '%realpath' => $realpath));
     }
     else {
@@ -548,18 +536,18 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
 
   // Build a destination URI if necessary.
   if (!isset($destination)) {
-    $destination = file_build_uri(drupal_basename($source));
+    $destination = file_build_uri(File::basename($source));
   }
 
 
   // Prepare the destination directory.
   if (file_prepare_directory($destination)) {
     // The destination is already a directory, so append the source basename.
-    $destination = file_stream_wrapper_uri_normalize($destination . '/' . drupal_basename($source));
+    $destination = file_stream_wrapper_uri_normalize($destination . '/' . File::basename($source));
   }
   else {
     // Perhaps $destination is a dir/file?
-    $dirname = drupal_dirname($destination);
+    $dirname = File::dirname($destination);
     if (!file_prepare_directory($dirname)) {
       // The destination is not valid.
       watchdog('file', 'File %file could not be copied because the destination directory %destination is not configured correctly.', array('%file' => $original_source, '%destination' => $dirname));
@@ -577,8 +565,8 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
   }
 
   // Assert that the source and destination filenames are not the same.
-  $real_source = drupal_realpath($source);
-  $real_destination = drupal_realpath($destination);
+  $real_source = File::realpath($source);
+  $real_destination = File::realpath($destination);
   if ($source == $destination || ($real_source !== FALSE) && ($real_source == $real_destination)) {
     drupal_set_message(t('The specified file %file was not copied because it would overwrite itself.', array('%file' => $source)), 'error');
     watchdog('file', 'File %file could not be copied because it would overwrite itself.', array('%file' => $source));
@@ -597,7 +585,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST
   }
 
   // Set the permissions on the new file.
-  drupal_chmod($destination);
+  File::chmod($destination);
 
   return $destination;
 }
@@ -613,16 +601,16 @@ function file_build_uri($path) {
 /**
  * Determines the destination path for a file.
  *
- * @param $destination
+ * @param string $destination
  *   A string specifying the desired final URI or filepath.
- * @param $replace
+ * @param int $replace
  *   Replace behavior when the destination file already exists.
  *   - FILE_EXISTS_REPLACE - Replace the existing file.
  *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
  *       unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  *
- * @return
+ * @return string|bool
  *   The destination filepath, or FALSE if the file already exists
  *   and FILE_EXISTS_ERROR is specified.
  */
@@ -634,8 +622,8 @@ function file_destination($destination, $replace) {
         break;
 
       case FILE_EXISTS_RENAME:
-        $basename = drupal_basename($destination);
-        $directory = drupal_dirname($destination);
+        $basename = File::basename($destination);
+        $directory = File::dirname($destination);
         $destination = file_create_filename($basename, $directory);
         break;
 
@@ -650,20 +638,20 @@ function file_destination($destination, $replace) {
 /**
  * Moves a file to a new location without database changes or hook invocation.
  *
- * @param $source
+ * @param string $source
  *   A string specifying the filepath or URI of the original file.
- * @param $destination
+ * @param string $destination
  *   A string containing the destination that $source should be moved to.
  *   This must be a stream wrapper URI. If this value is omitted, Drupal's
  *   default files scheme will be used, usually "public://".
- * @param $replace
+ * @param int $replace
  *   Replace behavior when the destination file already exists:
  *   - FILE_EXISTS_REPLACE - Replace the existing file.
  *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
  *       unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  *
- * @return
+ * @return string|bool
  *   The URI of the moved file, or FALSE in the event of an error.
  *
  * @see file_move()
@@ -711,7 +699,7 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
   $original = $filename;
 
   // Allow potentially insecure uploads for very savvy users and admin
-  if (!config('system.file')->get('allow_insecure_uploads')) {
+  if (!Drupal::config('system.file')->get('allow_insecure_uploads')) {
     // Remove any null bytes. See http://php.net/manual/en/security.filesystem.nullbytes.php
     $filename = str_replace(chr(0), '', $filename);
 
@@ -745,10 +733,10 @@ function file_munge_filename($filename, $extensions, $alerts = TRUE) {
 /**
  * Undoes the effect of file_munge_filename().
  *
- * @param $filename
+ * @param string $filename
  *   String with the filename to be unmunged.
  *
- * @return
+ * @return string
  *   An unmunged filename string.
  */
 function file_unmunge_filename($filename) {
@@ -761,12 +749,12 @@ function file_unmunge_filename($filename) {
  * If a file with the specified name already exists, an alternative will be
  * used.
  *
- * @param $basename
+ * @param string $basename
  *   String filename
- * @param $directory
+ * @param string $directory
  *   String containing the directory or parent URI.
  *
- * @return
+ * @return string
  *   File path consisting of $directory and a unique filename based off
  *   of $basename.
  */
@@ -817,14 +805,14 @@ function file_create_filename($basename, $directory) {
  * file usages instead. That will automatically mark the file as temporary and
  * remove it during cleanup.
  *
- * @param $fid
+ * @param int $fid
  *   The file id.
  *
  * @see file_unmanaged_delete()
  * @see file_usage()->listUsage()
  */
 function file_delete($fid) {
-  return file_delete_multiple(array($fid));
+  file_delete_multiple(array($fid));
 }
 
 /**
@@ -834,8 +822,8 @@ function file_delete($fid) {
  * file usages instead. That will automatically mark the file as temporary and
  * remove it during cleanup.
  *
- * @param $fid
- *   The file id.
+ * @param array $fids
+ *   An array of file IDs.
  *
  * @see file_unmanaged_delete()
  * @see file_usage()->listUsage()
@@ -850,10 +838,10 @@ function file_delete_multiple(array $fids) {
  * This function should be used when the file to be deleted does not have an
  * entry recorded in the files table.
  *
- * @param $path
+ * @param string $path
  *   A string containing a file path or (streamwrapper) URI.
  *
- * @return
+ * @return bool
  *   TRUE for success or path does not exist, or FALSE in the event of an
  *   error.
  *
@@ -866,7 +854,7 @@ function file_unmanaged_delete($path) {
     return FALSE;
   }
   if (is_file($path)) {
-    return drupal_unlink($path);
+    return File::unlink($path);
   }
   // Return TRUE for non-existent file, but log that nothing was actually
   // deleted, as the current state is the intended result.
@@ -892,14 +880,14 @@ function file_unmanaged_delete($path) {
  *
  * Note that this only deletes visible files with write permission.
  *
- * @param $path
+ * @param string $path
  *   A string containing either an URI or a file or directory path.
- * @param $callback
+ * @param callable $callback
  *   (optional) Callback function to run on each file prior to deleting it and
  *   on each directory prior to traversing it. For example, can be used to
  *   modify permissions.
  *
- * @return
+ * @return bool
  *   TRUE for success or if path does not exist, FALSE in the event of an
  *   error.
  *
@@ -920,48 +908,22 @@ function file_unmanaged_delete_recursive($path, $callback = NULL) {
     }
     $dir->close();
 
-    return drupal_rmdir($path);
+    return File::rmdir($path);
   }
   return file_unmanaged_delete($path);
 }
 
-
-
 /**
  * Moves an uploaded file to a new location.
  *
- * PHP's move_uploaded_file() does not properly support streams if safe_mode
- * or open_basedir are enabled, so this function fills that gap.
- *
- * Compatibility: normal paths and stream wrappers.
- *
- * @param $filename
- *   The filename of the uploaded file.
- * @param $uri
- *   A string containing the destination URI of the file.
- *
- * @return
- *   TRUE on success, or FALSE on failure.
- *
  * @see move_uploaded_file()
  * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::moveUploadedFile().
  */
 function drupal_move_uploaded_file($filename, $uri) {
-  $result = @move_uploaded_file($filename, $uri);
-  // PHP's move_uploaded_file() does not properly support streams if safe_mode
-  // or open_basedir are enabled so if the move failed, try finding a real path
-  // and retry the move operation.
-  if (!$result) {
-    if ($realpath = drupal_realpath($uri)) {
-      $result = move_uploaded_file($filename, $realpath);
-    }
-    else {
-      $result = move_uploaded_file($filename, $uri);
-    }
-  }
-
-  return $result;
+  return File::moveUploadedFile($filename, $uri);
 }
 
 /**
@@ -971,28 +933,28 @@ function drupal_move_uploaded_file($filename, $uri) {
  * saved to the {file_managed} table and none of the file_* hooks will be
  * called.
  *
- * @param $data
+ * @param string $data
  *   A string containing the contents of the file.
- * @param $destination
+ * @param string $destination
  *   A string containing the destination location. This must be a stream wrapper
  *   URI. If no value is provided, a randomized name will be generated and the
  *   file will be saved using Drupal's default files scheme, usually
  *   "public://".
- * @param $replace
+ * @param int $replace
  *   Replace behavior when the destination file already exists:
  *   - FILE_EXISTS_REPLACE - Replace the existing file.
  *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
  *                          unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  *
- * @return
+ * @return string|bool
  *   A string with the path of the resulting file, or FALSE on error.
  *
  * @see file_save_data()
  */
 function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
   // Write the data to a temporary file.
-  $temp_name = drupal_tempnam('temporary://', 'file');
+  $temp_name = File::tempnam('temporary://', 'file');
   if (file_put_contents($temp_name, $data) === FALSE) {
     drupal_set_message(t('The file could not be created.'), 'error');
     return FALSE;
@@ -1009,11 +971,11 @@ function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EX
  * prevents hidden files and directories (such as SVN working directories)
  * from being scanned.
  *
- * @param $dir
+ * @param string $dir
  *   The base directory or URI to scan, without trailing slash.
- * @param $mask
+ * @param string $mask
  *   The preg_match() regular expression of the files to find.
- * @param $options
+ * @param array $options
  *   An associative array of additional options, with the following elements:
  *   - 'nomask': The preg_match() regular expression of the files to ignore.
  *     Defaults to '/(\.\.?|CVS)$/'.
@@ -1027,11 +989,11 @@ function file_unmanaged_save_data($data, $destination = NULL, $replace = FILE_EX
  *     extension. Defaults to 'uri'.
  *   - 'min_depth': Minimum depth of directories to return files from. Defaults
  *     to 0.
- * @param $depth
+ * @param int $depth
  *   Current depth of recursion. This parameter is only used internally and
  *   should not be passed in.
  *
- * @return
+ * @return array
  *   An associative array (keyed on the chosen key) of objects with 'uri',
  *   'filename', and 'name' members corresponding to the matching files.
  */
@@ -1045,6 +1007,7 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
     'min_depth' => 0,
   );
   // Normalize $dir only once.
+  $dir_has_slash = FALSE;
   if ($depth == 0) {
     $dir = file_stream_wrapper_uri_normalize($dir);
     $dir_has_slash = (substr($dir, -1) === '/');
@@ -1099,7 +1062,7 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
 /**
  * Determines the maximum file upload size by querying the PHP settings.
  *
- * @return
+ * @return int
  *   A file size limit in bytes based on the PHP upload_max_filesize and
  *   post_max_size
  */
@@ -1123,16 +1086,16 @@ function file_upload_max_size() {
 /**
  * Determines an Internet Media Type or MIME type from a filename.
  *
- * @param $uri
+ * @param string $uri
  *   A string containing the URI, path, or filename.
- * @param $mapping
+ * @param array|null $mapping
  *   An optional map of extensions to their mimetypes, in the form:
  *    - 'mimetypes': a list of mimetypes, keyed by an identifier,
  *    - 'extensions': the mapping itself, an associative array in which
  *      the key is the extension (lowercase) and the value is the mimetype
  *      identifier. If $mapping is NULL file_mimetype_mapping() is called.
  *
- * @return
+ * @return string
  *   The internet media type registered for the extension or
  *   application/octet-stream for unknown extensions.
  *
@@ -1152,351 +1115,103 @@ function file_get_mimetype($uri, $mapping = NULL) {
 /**
  * Sets the permissions on a file or directory.
  *
- * This function will use the system.file:chmod.directory and
- * system.file:chmod.file configuration for the default modes for directories
- * and uploaded/generated files. By default these will give everyone read access
- * so that users accessing the files with a user account without the webserver
- * group (e.g. via FTP) can read these files, and give group write permissions
- * so webserver group members (e.g. a vhost account) can alter files uploaded
- * and owned by the webserver.
- *
- * PHP's chmod does not support stream wrappers so we use our wrapper
- * implementation which interfaces with chmod() by default. Contrib wrappers
- * may override this behavior in their implementations as needed.
- *
- * @param $uri
- *   A string containing a URI file, or directory path.
- * @param $mode
- *   Integer value for the permissions. Consult PHP chmod() documentation for
- *   more information.
- *
- * @return bool
- *   TRUE for success, FALSE in the event of an error.
- *
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::chmod().
  */
 function drupal_chmod($uri, $mode = NULL) {
-  if (!isset($mode)) {
-    // Configuration system stores default modes as strings. We use octdec() so
-    // that the octal permission numbers can be expressed as integers or strings
-    // and will be converted correctly in both cases.
-    if (is_dir($uri)) {
-      $mode = octdec(config('system.file')->get('chmod.directory'));
-      if (!$mode) {
-        $mode = 0775;
-      }
-    }
-    else {
-      $mode = octdec(config('system.file')->get('chmod.file'));
-      if (!$mode) {
-        $mode = 0664;
-      }
-    }
-  }
-
-  // If this URI is a stream, pass it off to the appropriate stream wrapper.
-  // Otherwise, attempt PHP's chmod. This allows use of drupal_chmod even
-  // for unmanaged files outside of the stream wrapper interface.
-  if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
-    if ($wrapper->chmod($mode)) {
-      return TRUE;
-    }
-  }
-  else {
-    if (@chmod($uri, $mode)) {
-      return TRUE;
-    }
-  }
-
-  watchdog('file', 'The file permissions could not be set on %uri.', array('%uri' => $uri), WATCHDOG_ERROR);
-  return FALSE;
+  return File::chmod($uri, $mode);
 }
 
 /**
  * Deletes a file.
  *
- * PHP's unlink() is broken on Windows, as it can fail to remove a file
- * when it has a read-only flag set.
- *
- * @param $uri
- *   A URI or pathname.
- * @param $context
- *   Refer to http://php.net/manual/ref.stream.php
- *
- * @return
- *   Boolean TRUE on success, or FALSE on failure.
- *
  * @see unlink()
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::unlink().
  */
 function drupal_unlink($uri, $context = NULL) {
-  $scheme = file_uri_scheme($uri);
-  if (!file_stream_wrapper_valid_scheme($scheme) && (substr(PHP_OS, 0, 3) == 'WIN')) {
-    chmod($uri, 0600);
-  }
-  if ($context) {
-    return unlink($uri, $context);
-  }
-  else {
-    return unlink($uri);
-  }
+  return File::unlink($uri, $context);
 }
 
 /**
  * Resolves the absolute filepath of a local URI or filepath.
  *
- * The use of drupal_realpath() is discouraged, because it does not work for
- * remote URIs. Except in rare cases, URIs should not be manually resolved.
- *
- * Only use this function if you know that the stream wrapper in the URI uses
- * the local file system, and you need to pass an absolute path to a function
- * that is incompatible with stream URIs.
- *
- * @param string $uri
- *   A stream wrapper URI or a filepath, possibly including one or more symbolic
- *   links.
- *
- * @return string|false
- *   The absolute local filepath (with no symbolic links), or FALSE on failure.
- *
  * @see Drupal\Core\StreamWrapper\StreamWrapperInterface::realpath()
  * @see http://php.net/manual/function.realpath.php
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::realpath().
  */
 function drupal_realpath($uri) {
-  // If this URI is a stream, pass it off to the appropriate stream wrapper.
-  // Otherwise, attempt PHP's realpath. This allows use of drupal_realpath even
-  // for unmanaged files outside of the stream wrapper interface.
-  if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
-    return $wrapper->realpath();
-  }
-
-  return realpath($uri);
+  return File::realpath($uri);
 }
 
 /**
  * Gets the name of the directory from a given path.
  *
- * PHP's dirname() does not properly pass streams, so this function fills
- * that gap. It is backwards compatible with normal paths and will use
- * PHP's dirname() as a fallback.
- *
- * Compatibility: normal paths and stream wrappers.
- *
- * @param $uri
- *   A URI or path.
- *
- * @return
- *   A string containing the directory name.
- *
  * @see dirname()
  * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::dirname().
  */
 function drupal_dirname($uri) {
-  $scheme = file_uri_scheme($uri);
-
-  if (file_stream_wrapper_valid_scheme($scheme)) {
-    return file_stream_wrapper_get_instance_by_scheme($scheme)->dirname($uri);
-  }
-  else {
-    return dirname($uri);
-  }
+  return File::dirname($uri);
 }
 
 /**
  * Gets the filename from a given path.
  *
- * PHP's basename() does not properly support streams or filenames beginning
- * with a non-US-ASCII character.
- *
  * @see http://bugs.php.net/bug.php?id=37738
  * @see basename()
  *
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::basename().
  */
 function drupal_basename($uri, $suffix = NULL) {
-  $separators = '/';
-  if (DIRECTORY_SEPARATOR != '/') {
-    // For Windows OS add special separator.
-    $separators .= DIRECTORY_SEPARATOR;
-  }
-  // Remove right-most slashes when $uri points to directory.
-  $uri = rtrim($uri, $separators);
-  // Returns the trailing part of the $uri starting after one of the directory
-  // separators.
-  $filename = preg_match('@[^' . preg_quote($separators, '@') . ']+$@', $uri, $matches) ? $matches[0] : '';
-  // Cuts off a suffix from the filename.
-  if ($suffix) {
-    $filename = preg_replace('@' . preg_quote($suffix, '@') . '$@', '', $filename);
-  }
-  return $filename;
+  return File::basename($uri, $suffix);
 }
 
 /**
  * Creates a directory, optionally creating missing components in the path to
  * the directory.
  *
- * When PHP's mkdir() creates a directory, the requested mode is affected by the
- * process's umask. This function overrides the umask and sets the mode
- * explicitly for all directory components created.
- *
- * @param $uri
- *   A URI or pathname.
- * @param $mode
- *   Mode given to created directories. Defaults to the directory mode
- *   configured in the Drupal installation. It must have a leading zero.
- * @param $recursive
- *   Create directories recursively, defaults to FALSE. Cannot work with a mode
- *   which denies writing or execution to the owner of the process.
- * @param $context
- *   Refer to http://php.net/manual/ref.stream.php
- *
- * @return
- *   Boolean TRUE on success, or FALSE on failure.
- *
  * @see mkdir()
  * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::mkdir().
  */
 function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) {
-  if (!isset($mode)) {
-    // Configuration system stores default mode as strings.
-    $mode = FALSE;
-    // During early update there's no container.
-    if (is_object(Drupal::getContainer())) {
-      $mode = octdec(config('system.file')->get('chmod.directory'));
-    }
-    if (!$mode) {
-      $mode = 0775;
-    }
-  }
-
-  // If the URI has a scheme, don't override the umask - schemes can handle this
-  // issue in their own implementation.
-  if (file_uri_scheme($uri)) {
-    return _drupal_mkdir_call($uri, $mode, $recursive, $context);
-  }
-
-  // If recursive, create each missing component of the parent directory
-  // individually and set the mode explicitly to override the umask.
-  if ($recursive) {
-    // Ensure the path is using DIRECTORY_SEPARATOR.
-    $uri = str_replace('/', DIRECTORY_SEPARATOR, $uri);
-    // Determine the components of the path.
-    $components = explode(DIRECTORY_SEPARATOR, $uri);
-    array_pop($components);
-    $recursive_path = '';
-    foreach ($components as $component) {
-      $recursive_path .= $component;
-
-      if (!file_exists($recursive_path)) {
-        if (!_drupal_mkdir_call($recursive_path, $mode, FALSE, $context)) {
-          return FALSE;
-        }
-        // Not necessary to use drupal_chmod() as there is no scheme.
-        if (!chmod($recursive_path, $mode)) {
-          return FALSE;
-        }
-      }
-
-      $recursive_path .= DIRECTORY_SEPARATOR;
-    }
-  }
-
-  // Do not check if the top-level directory already exists, as this condition
-  // must cause this function to fail.
-  if (!_drupal_mkdir_call($uri, $mode, FALSE, $context)) {
-    return FALSE;
-  }
-  // Not necessary to use drupal_chmod() as there is no scheme.
-  return chmod($uri, $mode);
-}
-
-/**
- * Helper function. Ensures we don't pass a NULL as a context resource to
- * mkdir().
- *
- * @see drupal_mkdir()
- */
-function _drupal_mkdir_call($uri, $mode, $recursive, $context) {
-  if (is_null($context)) {
-    return mkdir($uri, $mode, $recursive);
-  }
-  else {
-    return mkdir($uri, $mode, $recursive, $context);
-  }
+  return File::mkdir($uri, $mode, $recursive, $context);
 }
 
 /**
  * Removes a directory.
  *
- * PHP's rmdir() is broken on Windows, as it can fail to remove a directory
- * when it has a read-only flag set.
- *
- * @param $uri
- *   A URI or pathname.
- * @param $context
- *   Refer to http://php.net/manual/ref.stream.php
- *
- * @return
- *   Boolean TRUE on success, or FALSE on failure.
- *
  * @see rmdir()
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::rmdir().
  */
 function drupal_rmdir($uri, $context = NULL) {
-  $scheme = file_uri_scheme($uri);
-  if (!file_stream_wrapper_valid_scheme($scheme) && (substr(PHP_OS, 0, 3) == 'WIN')) {
-    chmod($uri, 0700);
-  }
-  if ($context) {
-    return rmdir($uri, $context);
-  }
-  else {
-    return rmdir($uri);
-  }
+  return File::rmdir($uri, $context);
 }
 
 /**
  * Creates a file with a unique filename in the specified directory.
  *
- * PHP's tempnam() does not return a URI like we want. This function
- * will return a URI if given a URI, or it will return a filepath if
- * given a filepath.
- *
- * Compatibility: normal paths and stream wrappers.
- *
- * @param $directory
- *   The directory where the temporary filename will be created.
- * @param $prefix
- *   The prefix of the generated temporary filename.
- *   Note: Windows uses only the first three characters of prefix.
- *
- * @return
- *   The new temporary filename, or FALSE on failure.
- *
  * @see tempnam()
  * @see http://drupal.org/node/515192
  * @ingroup php_wrappers
+ *
+ * @deprecated Use \Drupal\Core\Utility\File::tempnam().
  */
 function drupal_tempnam($directory, $prefix) {
-  $scheme = file_uri_scheme($directory);
-
-  if (file_stream_wrapper_valid_scheme($scheme)) {
-    $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
-
-    if ($filename = tempnam($wrapper->getDirectoryPath(), $prefix)) {
-      return $scheme . '://' . drupal_basename($filename);
-    }
-    else {
-      return FALSE;
-    }
-  }
-  else {
-    // Handle as a normal tempnam() call.
-    return tempnam($directory, $prefix);
-  }
+  return File::tempnam($directory, $prefix);
 }
 
 /**
@@ -1506,7 +1221,7 @@ function drupal_tempnam($directory, $prefix) {
  *   A string containing the path to the temporary directory.
  */
 function file_directory_temp() {
-  $config = config('system.file');
+  $config = Drupal::config('system.file');
   $temporary_directory = $config->get('path.temporary');
   if (empty($temporary_directory)) {
     $temporary_directory = file_directory_os_temp();
diff --git a/core/lib/Drupal/Core/Utility/File.php b/core/lib/Drupal/Core/Utility/File.php
new file mode 100644
index 0000000..ef4dfb9
--- /dev/null
+++ b/core/lib/Drupal/Core/Utility/File.php
@@ -0,0 +1,456 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Utility\File.
+ */
+
+namespace Drupal\Core\Utility;
+
+/**
+ * Provides helpers to operate on files and stream wrappers.
+ */
+class File {
+
+  /**
+   * Moves an uploaded file to a new location.
+   *
+   * PHP's move_uploaded_file() does not properly support streams if safe_mode
+   * or open_basedir are enabled, so this function fills that gap.
+   *
+   * Compatibility: normal paths and stream wrappers.
+   *
+   * @param string $filename
+   *   The filename of the uploaded file.
+   * @param string $uri
+   *   A string containing the destination URI of the file.
+   *
+   * @return bool
+   *   TRUE on success, or FALSE on failure.
+   *
+   * @see move_uploaded_file()
+   * @see http://drupal.org/node/515192
+   * @ingroup php_wrappers
+   */
+  public static function moveUploadedFile($filename, $uri) {
+    $result = @move_uploaded_file($filename, $uri);
+    // PHP's move_uploaded_file() does not properly support streams if safe_mode
+    // or open_basedir are enabled so if the move failed, try finding a real path
+    // and retry the move operation.
+    if (!$result) {
+      if ($realpath = static::realpath($uri)) {
+        $result = move_uploaded_file($filename, $realpath);
+      }
+      else {
+        $result = move_uploaded_file($filename, $uri);
+      }
+    }
+
+    return $result;
+  }
+
+  /**
+   * Sets the permissions on a file or directory.
+   *
+   * This function will use the system.file:chmod.directory and
+   * system.file:chmod.file configuration for the default modes for directories
+   * and uploaded/generated files. By default these will give everyone read access
+   * so that users accessing the files with a user account without the webserver
+   * group (e.g. via FTP) can read these files, and give group write permissions
+   * so webserver group members (e.g. a vhost account) can alter files uploaded
+   * and owned by the webserver.
+   *
+   * PHP's chmod does not support stream wrappers so we use our wrapper
+   * implementation which interfaces with chmod() by default. Contrib wrappers
+   * may override this behavior in their implementations as needed.
+   *
+   * @param string $uri
+   *   A string containing a URI file, or directory path.
+   * @param int $mode
+   *   Integer value for the permissions. Consult PHP chmod() documentation for
+   *   more information.
+   *
+   * @return bool
+   *   TRUE for success, FALSE in the event of an error.
+   *
+   * @ingroup php_wrappers
+   */
+  public static function chmod($uri, $mode = NULL) {
+    if (!isset($mode)) {
+      // Configuration system stores default modes as strings. We use octdec() so
+      // that the octal permission numbers can be expressed as integers or strings
+      // and will be converted correctly in both cases.
+      $config = \Drupal::config('system.file');
+      if (is_dir($uri)) {
+        $mode = octdec($config->get('chmod.directory'));
+        if (!$mode) {
+          $mode = 0775;
+        }
+      }
+      else {
+        $mode = octdec($config->get('chmod.file'));
+        if (!$mode) {
+          $mode = 0664;
+        }
+      }
+    }
+
+    // If this URI is a stream, pass it off to the appropriate stream wrapper.
+    // Otherwise, attempt PHP's chmod. This allows use of
+    // \Drupal\Core\Utility\File::chmod() even for unmanaged files outside of
+    // the stream wrapper interface.
+    if ($wrapper = static::getStreamWrapperManager()->getInstance(array('uri' => $uri))) {
+      if ($wrapper->chmod($mode)) {
+        return TRUE;
+      }
+    }
+    else {
+      if (@chmod($uri, $mode)) {
+        return TRUE;
+      }
+    }
+
+    watchdog('file', 'The file permissions could not be set on %uri.', array('%uri' => $uri), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  /**
+   * Deletes a file.
+   *
+   * PHP's unlink() is broken on Windows, as it can fail to remove a file
+   * when it has a read-only flag set.
+   *
+   * @param string $uri
+   *   A URI or pathname.
+   * @param resource|null $context
+   *   Refer to http://php.net/manual/ref.stream.php
+   *
+   * @return bool
+   *   Boolean TRUE on success, or FALSE on failure.
+   *
+   * @see unlink()
+   * @ingroup php_wrappers
+   */
+  public static function unlink($uri, $context = NULL) {
+    $scheme = static::uriScheme($uri);
+    if (!static::validScheme($scheme) && (substr(PHP_OS, 0, 3) == 'WIN')) {
+      chmod($uri, 0600);
+    }
+    if ($context) {
+      return unlink($uri, $context);
+    }
+    else {
+      return unlink($uri);
+    }
+  }
+
+  /**
+   * Resolves the absolute filepath of a local URI or filepath.
+   *
+   * The use of \Drupal\Core\Utility\File::realpath() is discouraged, because it
+   * does not work for remote URIs. Except in rare cases, URIs should not be
+   * manually resolved.
+   *
+   * Only use this function if you know that the stream wrapper in the URI uses
+   * the local file system, and you need to pass an absolute path to a function
+   * that is incompatible with stream URIs.
+   *
+   * @param string $uri
+   *   A stream wrapper URI or a filepath, possibly including one or more
+   *   symbolic links.
+   *
+   * @return string|bool
+   *   The absolute local filepath (with no symbolic links) or FALSE on failure.
+   *
+   * @see Drupal\Core\StreamWrapper\StreamWrapperInterface::realpath()
+   * @see http://php.net/manual/function.realpath.php
+   * @ingroup php_wrappers
+   */
+  public static function realpath($uri) {
+    // If this URI is a stream, pass it off to the appropriate stream wrapper.
+    // Otherwise, attempt PHP's realpath. This allows use of
+    // \Drupal\Core\Utility\File::realpath even for unmanaged files outside of
+    // the stream wrapper interface.
+    if ($wrapper = static::getStreamWrapperManager()->getInstance(array('uri' => $uri))) {
+      return $wrapper->realpath();
+    }
+
+    return realpath($uri);
+  }
+
+  /**
+   * Gets the name of the directory from a given path.
+   *
+   * PHP's dirname() does not properly pass streams, so this function fills
+   * that gap. It is backwards compatible with normal paths and will use
+   * PHP's dirname() as a fallback.
+   *
+   * Compatibility: normal paths and stream wrappers.
+   *
+   * @param string $uri
+   *   A URI or path.
+   *
+   * @return string
+   *   A string containing the directory name.
+   *
+   * @see dirname()
+   * @see http://drupal.org/node/515192
+   * @ingroup php_wrappers
+   */
+  public static function dirname($uri) {
+    $scheme = static::uriScheme($uri);
+
+    if (static::validScheme($scheme)) {
+      return static::getStreamWrapperManager()->getInstance(array('scheme' => $scheme))->dirname($uri);
+    }
+    else {
+      return dirname($uri);
+    }
+  }
+
+  /**
+   * Gets the filename from a given path.
+   *
+   * PHP's basename() does not properly support streams or filenames beginning
+   * with a non-US-ASCII character.
+   *
+   * @see http://bugs.php.net/bug.php?id=37738
+   * @see basename()
+   *
+   * @ingroup php_wrappers
+   */
+  public static function basename($uri, $suffix = NULL) {
+    $separators = '/';
+    if (DIRECTORY_SEPARATOR != '/') {
+      // For Windows OS add special separator.
+      $separators .= DIRECTORY_SEPARATOR;
+    }
+    // Remove right-most slashes when $uri points to directory.
+    $uri = rtrim($uri, $separators);
+    // Returns the trailing part of the $uri starting after one of the directory
+    // separators.
+    $filename = preg_match('@[^' . preg_quote($separators, '@') . ']+$@', $uri, $matches) ? $matches[0] : '';
+    // Cuts off a suffix from the filename.
+    if ($suffix) {
+      $filename = preg_replace('@' . preg_quote($suffix, '@') . '$@', '', $filename);
+    }
+    return $filename;
+  }
+
+  /**
+   * Creates a directory, optionally creating missing components in the path to
+   * the directory.
+   *
+   * When PHP's mkdir() creates a directory, the requested mode is affected by the
+   * process's umask. This function overrides the umask and sets the mode
+   * explicitly for all directory components created.
+   *
+   * @param string $uri
+   *   A URI or pathname.
+   * @param int $mode
+   *   Mode given to created directories. Defaults to the directory mode
+   *   configured in the Drupal installation. It must have a leading zero.
+   * @param bool $recursive
+   *   Create directories recursively, defaults to FALSE. Cannot work with a mode
+   *   which denies writing or execution to the owner of the process.
+   * @param resource|null $context
+   *   Refer to http://php.net/manual/ref.stream.php
+   *
+   * @return bool
+   *   Boolean TRUE on success, or FALSE on failure.
+   *
+   * @see mkdir()
+   * @see http://drupal.org/node/515192
+   * @ingroup php_wrappers
+   */
+  public static function mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) {
+    if (!isset($mode)) {
+      // Configuration system stores default mode as strings.
+      $mode = FALSE;
+      // During early update there's no container.
+      if (is_object(\Drupal::getContainer())) {
+        $mode = octdec(\Drupal::config('system.file')->get('chmod.directory'));
+      }
+      if (!$mode) {
+        $mode = 0775;
+      }
+    }
+
+    // If the URI has a scheme, don't override the umask - schemes can handle this
+    // issue in their own implementation.
+    if (static::uriScheme($uri)) {
+      return static::mkdirCall($uri, $mode, $recursive, $context);
+    }
+
+    // If recursive, create each missing component of the parent directory
+    // individually and set the mode explicitly to override the umask.
+    if ($recursive) {
+      // Ensure the path is using DIRECTORY_SEPARATOR.
+      $uri = str_replace('/', DIRECTORY_SEPARATOR, $uri);
+      // Determine the components of the path.
+      $components = explode(DIRECTORY_SEPARATOR, $uri);
+      array_pop($components);
+      $recursive_path = '';
+      foreach ($components as $component) {
+        $recursive_path .= $component;
+
+        if (!file_exists($recursive_path)) {
+          if (!static::mkdirCall($recursive_path, $mode, FALSE, $context)) {
+            return FALSE;
+          }
+          // Not necessary to use \Drupal\Core\Utility\File::chmod() as there is
+          // no scheme.
+          if (!chmod($recursive_path, $mode)) {
+            return FALSE;
+          }
+        }
+
+        $recursive_path .= DIRECTORY_SEPARATOR;
+      }
+    }
+
+    // Do not check if the top-level directory already exists, as this condition
+    // must cause this function to fail.
+    if (!static::mkdirCall($uri, $mode, FALSE, $context)) {
+      return FALSE;
+    }
+    // Not necessary to use \Drupal\Core\Utility\File::chmod() as there is no scheme.
+    return chmod($uri, $mode);
+  }
+
+  /**
+   * Removes a directory.
+   *
+   * PHP's rmdir() is broken on Windows, as it can fail to remove a directory
+   * when it has a read-only flag set.
+   *
+   * @param string $uri
+   *   A URI or pathname.
+   * @param resource|null $context
+   *   Refer to http://php.net/manual/ref.stream.php
+   *
+   * @return bool
+   *   Boolean TRUE on success, or FALSE on failure.
+   *
+   * @see rmdir()
+   * @ingroup php_wrappers
+   */
+  public static function rmdir($uri, $context = NULL) {
+    $scheme = static::uriScheme($uri);
+    if (!static::validScheme($scheme) && (substr(PHP_OS, 0, 3) == 'WIN')) {
+      chmod($uri, 0700);
+    }
+    if ($context) {
+      return rmdir($uri, $context);
+    }
+    else {
+      return rmdir($uri);
+    }
+  }
+
+  /**
+   * Creates a file with a unique filename in the specified directory.
+   *
+   * PHP's tempnam() does not return a URI like we want. This function
+   * will return a URI if given a URI, or it will return a filepath if
+   * given a filepath.
+   *
+   * Compatibility: normal paths and stream wrappers.
+   *
+   * @param string $directory
+   *   The directory where the temporary filename will be created.
+   * @param string $prefix
+   *   The prefix of the generated temporary filename.
+   *   Note: Windows uses only the first three characters of prefix.
+   *
+   * @return string|bool
+   *   The new temporary filename, or FALSE on failure.
+   *
+   * @see tempnam()
+   * @see http://drupal.org/node/515192
+   * @ingroup php_wrappers
+   */
+  public static function tempnam($directory, $prefix) {
+    $scheme = static::uriScheme($directory);
+
+    if (static::validScheme($scheme)) {
+      $wrapper = static::getStreamWrapperManager()->getInstance(array('scheme' => $scheme));
+
+      if ($filename = tempnam($wrapper->getDirectoryPath(), $prefix)) {
+        return $scheme . '://' . static::basename($filename);
+      }
+      else {
+        return FALSE;
+      }
+    }
+    else {
+      // Handle as a normal tempnam() call.
+      return tempnam($directory, $prefix);
+    }
+  }
+
+  /**
+   * Helper function. Ensures we don't pass a NULL as a context resource to
+   * mkdir().
+   *
+   * @see \Drupal\Core\Utility\File::mkdir()
+   */
+  protected static function mkdirCall($uri, $mode, $recursive, $context) {
+    if (is_null($context)) {
+      return mkdir($uri, $mode, $recursive);
+    }
+    else {
+      return mkdir($uri, $mode, $recursive, $context);
+    }
+  }
+
+  /**
+   * Checks that the scheme of a stream URI is valid.
+   *
+   * Confirms that there is a registered stream handler for the provided scheme
+   * and that it is callable. This is useful if you want to confirm a valid
+   * scheme without creating a new instance of the registered handler.
+   *
+   * @param string $scheme
+   *   A URI scheme, a stream is referenced as "scheme://target".
+   *
+   * @return bool
+   *   Returns TRUE if the string is the name of a validated stream,
+   *   or FALSE if the scheme does not have a registered handler.
+   */
+  public static function validScheme($scheme) {
+    if (!$scheme) {
+      return FALSE;
+    }
+    $wrapper = static::getStreamWrapperManager()->getDefinition($scheme);
+    return !empty($wrapper) ? class_exists($wrapper['class']) : FALSE;
+  }
+
+  /**
+   * Returns the scheme of a URI (e.g. a stream).
+   *
+   * @param string $uri
+   *   A stream, referenced as "scheme://target".
+   *
+   * @return string|bool
+   *   A string containing the name of the scheme, or FALSE if none. For example,
+   *   the URI "public://example.txt" would return "public".
+   *
+   * @see file_uri_target()
+   */
+  public static function uriScheme($uri) {
+    $position = strpos($uri, '://');
+    return $position ? substr($uri, 0, $position) : FALSE;
+  }
+
+  /**
+   * Returns the stream wrapper manager.
+   *
+   * @return \Drupal\Core\StreamWrapper\StreamWrapperManager
+   *   The stream wrapper manager.
+   */
+  protected static function getStreamWrapperManager() {
+    return \Drupal::service('plugin.manager.stream_wrapper');
+  }
+
+}
