We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
MemoryFile and seek
# Expected behavior and actual behavior.

I am trying to download a file from AWS to a MemoryFile using boto3 (Sentinel 2 JP2). I would like to use `client.download_fileobj()` because I have finer control over the download : 

https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-example-download-file.html

## Steps to reproduce the problem.

```
import rasterio.io
import boto3

with rasterio.io.MemoryFile() as memfile:
    boto3.client('s3').download_fileobj(
        Fileobj=memfile,
        Bucket='sentinel-s2-l1c',
        Key='tiles/15/R/TN/2019/3/28/0/B02.jp2',
        ExtraArgs={'RequestPayer': 'requester'},
        Config=None)
```
Raises:

```
ValueError: seek position past end of file: 8388608
```

This works fine with io.BytesIO or the GCP storage client `blob.download_to_file()`.
There is a difference of behavior regarding the seek on positions w.r.t. BytesIO (the problem is probably linked to the multithreading in the AWS case?).

## Operating system
Ubuntu 18

## Rasterio version and provenance
rasterio-1.1.4-cp38-cp38-manylinux1_x86_64.whl


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rasterio/io.py`
Content:
```
1 """Classes capable of reading and writing datasets
2 
3 Instances of these classes are called dataset objects.
4 """
5 
6 import logging
7 
8 from rasterio._base import (
9     get_dataset_driver, driver_can_create, driver_can_create_copy)
10 from rasterio._io import (
11     DatasetReaderBase, DatasetWriterBase, BufferedDatasetWriterBase,
12     MemoryFileBase)
13 from rasterio.windows import WindowMethodsMixin
14 from rasterio.env import ensure_env, env_ctx_if_needed
15 from rasterio.transform import TransformMethodsMixin
16 from rasterio.path import UnparsedPath
17 
18 
19 log = logging.getLogger(__name__)
20 
21 
22 class DatasetReader(DatasetReaderBase, WindowMethodsMixin,
23                     TransformMethodsMixin):
24     """An unbuffered data and metadata reader"""
25 
26     def __repr__(self):
27         return "<{} DatasetReader name='{}' mode='{}'>".format(
28             self.closed and 'closed' or 'open', self.name, self.mode)
29 
30 
31 class DatasetWriter(DatasetWriterBase, WindowMethodsMixin,
32                     TransformMethodsMixin):
33     """An unbuffered data and metadata writer. Its methods write data
34     directly to disk.
35     """
36 
37     def __repr__(self):
38         return "<{} DatasetWriter name='{}' mode='{}'>".format(
39             self.closed and 'closed' or 'open', self.name, self.mode)
40 
41 
42 class BufferedDatasetWriter(BufferedDatasetWriterBase, WindowMethodsMixin,
43                             TransformMethodsMixin):
44     """Maintains data and metadata in a buffer, writing to disk or
45     network only when `close()` is called.
46 
47     This allows incremental updates to datasets using formats that don't
48     otherwise support updates, such as JPEG.
49     """
50 
51     def __repr__(self):
52         return "<{} BufferedDatasetWriter name='{}' mode='{}'>".format(
53             self.closed and 'closed' or 'open', self.name, self.mode)
54 
55 
56 class MemoryFile(MemoryFileBase):
57     """A BytesIO-like object, backed by an in-memory file.
58 
59     This allows formatted files to be read and written without I/O.
60 
61     A MemoryFile created with initial bytes becomes immutable. A
62     MemoryFile created without initial bytes may be written to using
63     either file-like or dataset interfaces.
64 
65     Examples
66     --------
67 
68     A GeoTIFF can be loaded in memory and accessed using the GeoTIFF
69     format driver
70 
71     >>> with open('tests/data/RGB.byte.tif', 'rb') as f, MemoryFile(f) as memfile:
72     ...     with memfile.open() as src:
73     ...         pprint.pprint(src.profile)
74     ...
75     {'count': 3,
76      'crs': CRS({'init': 'epsg:32618'}),
77      'driver': 'GTiff',
78      'dtype': 'uint8',
79      'height': 718,
80      'interleave': 'pixel',
81      'nodata': 0.0,
82      'tiled': False,
83      'transform': Affine(300.0379266750948, 0.0, 101985.0,
84            0.0, -300.041782729805, 2826915.0),
85      'width': 791}
86 
87     """
88     def __init__(self, file_or_bytes=None, filename=None, ext=''):
89         """Create a new file in memory
90 
91         Parameters
92         ----------
93         file_or_bytes : file-like object or bytes, optional
94             File or bytes holding initial data.
95         filename : str, optional
96             An optional filename. A unique one will otherwise be generated.
97         ext : str, optional
98             An optional extension.
99 
100         Returns
101         -------
102         MemoryFile
103         """
104         super(MemoryFile, self).__init__(
105             file_or_bytes=file_or_bytes, filename=filename, ext=ext)
106 
107     @ensure_env
108     def open(self, driver=None, width=None, height=None, count=None, crs=None,
109              transform=None, dtype=None, nodata=None, sharing=False, **kwargs):
110         """Open the file and return a Rasterio dataset object.
111 
112         If data has already been written, the file is opened in 'r'
113         mode. Otherwise, the file is opened in 'w' mode.
114 
115         Parameters
116         ----------
117         Note well that there is no `path` parameter: a `MemoryFile`
118         contains a single dataset and there is no need to specify a
119         path.
120 
121         Other parameters are optional and have the same semantics as the
122         parameters of `rasterio.open()`.
123         """
124         mempath = UnparsedPath(self.name)
125 
126         if self.closed:
127             raise IOError("I/O operation on closed file.")
128         if self.exists():
129             log.debug("VSI path: {}".format(mempath.path))
130             return DatasetReader(mempath, driver=driver, sharing=sharing, **kwargs)
131         else:
132             writer = get_writer_for_driver(driver)
133             return writer(mempath, 'w+', driver=driver, width=width,
134                           height=height, count=count, crs=crs,
135                           transform=transform, dtype=dtype,
136                           nodata=nodata, sharing=sharing, **kwargs)
137 
138     def __enter__(self):
139         self._env = env_ctx_if_needed()
140         self._env.__enter__()
141         return self
142 
143     def __exit__(self, *args, **kwargs):
144         self._env.__exit__()
145         self.close()
146 
147 
148 class ZipMemoryFile(MemoryFile):
149     """A read-only BytesIO-like object backed by an in-memory zip file.
150 
151     This allows a zip file containing formatted files to be read
152     without I/O.
153     """
154 
155     def __init__(self, file_or_bytes=None):
156         super(ZipMemoryFile, self).__init__(file_or_bytes, ext='zip')
157 
158     @ensure_env
159     def open(self, path, driver=None, sharing=False, **kwargs):
160         """Open a dataset within the zipped stream.
161 
162         Parameters
163         ----------
164         path : str
165             Path to a dataset in the zip file, relative to the root of the
166             archive.
167 
168         Other parameters are optional and have the same semantics as the
169         parameters of `rasterio.open()`.
170 
171         Returns
172         -------
173         A Rasterio dataset object
174         """
175         zippath = UnparsedPath('/vsizip{0}/{1}'.format(self.name, path.lstrip('/')))
176 
177         if self.closed:
178             raise IOError("I/O operation on closed file.")
179         return DatasetReader(zippath, driver=driver, sharing=sharing, **kwargs)
180 
181 
182 def get_writer_for_driver(driver):
183     """Return the writer class appropriate for the specified driver."""
184     if not driver:
185         raise ValueError("'driver' is required to write dataset.")
186     cls = None
187     if driver_can_create(driver):
188         cls = DatasetWriter
189     elif driver_can_create_copy(driver):  # pragma: no branch
190         cls = BufferedDatasetWriter
191     return cls
192 
193 
194 def get_writer_for_path(path, driver=None):
195     """Return the writer class appropriate for the existing dataset."""
196     if not driver:
197         driver = get_dataset_driver(path)
198     return get_writer_for_driver(driver)
199
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/rasterio/io.py b/rasterio/io.py
--- a/rasterio/io.py
+++ b/rasterio/io.py
@@ -85,7 +85,7 @@
      'width': 791}
 
     """
-    def __init__(self, file_or_bytes=None, filename=None, ext=''):
+    def __init__(self, file_or_bytes=None, dirname=None, filename=None, ext=''):
         """Create a new file in memory
 
         Parameters
@@ -102,7 +102,7 @@
         MemoryFile
         """
         super(MemoryFile, self).__init__(
-            file_or_bytes=file_or_bytes, filename=filename, ext=ext)
+            file_or_bytes=file_or_bytes, dirname=dirname, filename=filename, ext=ext)
 
     @ensure_env
     def open(self, driver=None, width=None, height=None, count=None, crs=None,
@@ -125,7 +125,7 @@
 
         if self.closed:
             raise IOError("I/O operation on closed file.")
-        if self.exists():
+        if len(self) > 0:
             log.debug("VSI path: {}".format(mempath.path))
             return DatasetReader(mempath, driver=driver, sharing=sharing, **kwargs)
         else:

{"golden_diff": "diff --git a/rasterio/io.py b/rasterio/io.py\n--- a/rasterio/io.py\n+++ b/rasterio/io.py\n@@ -85,7 +85,7 @@\n      'width': 791}\n \n     \"\"\"\n-    def __init__(self, file_or_bytes=None, filename=None, ext=''):\n+    def __init__(self, file_or_bytes=None, dirname=None, filename=None, ext=''):\n         \"\"\"Create a new file in memory\n \n         Parameters\n@@ -102,7 +102,7 @@\n         MemoryFile\n         \"\"\"\n         super(MemoryFile, self).__init__(\n-            file_or_bytes=file_or_bytes, filename=filename, ext=ext)\n+            file_or_bytes=file_or_bytes, dirname=dirname, filename=filename, ext=ext)\n \n     @ensure_env\n     def open(self, driver=None, width=None, height=None, count=None, crs=None,\n@@ -125,7 +125,7 @@\n \n         if self.closed:\n             raise IOError(\"I/O operation on closed file.\")\n-        if self.exists():\n+        if len(self) > 0:\n             log.debug(\"VSI path: {}\".format(mempath.path))\n             return DatasetReader(mempath, driver=driver, sharing=sharing, **kwargs)\n         else:\n", "issue": "MemoryFile and seek\n# Expected behavior and actual behavior.\r\n\r\nI am trying to download a file from AWS to a MemoryFile using boto3 (Sentinel 2 JP2). I would like to use `client.download_fileobj()` because I have finer control over the download : \r\n\r\nhttps://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-example-download-file.html\r\n\r\n## Steps to reproduce the problem.\r\n\r\n```\r\nimport rasterio.io\r\nimport boto3\r\n\r\nwith rasterio.io.MemoryFile() as memfile:\r\n    boto3.client('s3').download_fileobj(\r\n        Fileobj=memfile,\r\n        Bucket='sentinel-s2-l1c',\r\n        Key='tiles/15/R/TN/2019/3/28/0/B02.jp2',\r\n        ExtraArgs={'RequestPayer': 'requester'},\r\n        Config=None)\r\n```\r\nRaises:\r\n\r\n```\r\nValueError: seek position past end of file: 8388608\r\n```\r\n\r\nThis works fine with io.BytesIO or the GCP storage client `blob.download_to_file()`.\r\nThere is a difference of behavior regarding the seek on positions w.r.t. BytesIO (the problem is probably linked to the multithreading in the AWS case?).\r\n\r\n## Operating system\r\nUbuntu 18\r\n\r\n## Rasterio version and provenance\r\nrasterio-1.1.4-cp38-cp38-manylinux1_x86_64.whl\r\n\n", "before_files": [{"content": "\"\"\"Classes capable of reading and writing datasets\n\nInstances of these classes are called dataset objects.\n\"\"\"\n\nimport logging\n\nfrom rasterio._base import (\n    get_dataset_driver, driver_can_create, driver_can_create_copy)\nfrom rasterio._io import (\n    DatasetReaderBase, DatasetWriterBase, BufferedDatasetWriterBase,\n    MemoryFileBase)\nfrom rasterio.windows import WindowMethodsMixin\nfrom rasterio.env import ensure_env, env_ctx_if_needed\nfrom rasterio.transform import TransformMethodsMixin\nfrom rasterio.path import UnparsedPath\n\n\nlog = logging.getLogger(__name__)\n\n\nclass DatasetReader(DatasetReaderBase, WindowMethodsMixin,\n                    TransformMethodsMixin):\n    \"\"\"An unbuffered data and metadata reader\"\"\"\n\n    def __repr__(self):\n        return \"<{} DatasetReader name='{}' mode='{}'>\".format(\n            self.closed and 'closed' or 'open', self.name, self.mode)\n\n\nclass DatasetWriter(DatasetWriterBase, WindowMethodsMixin,\n                    TransformMethodsMixin):\n    \"\"\"An unbuffered data and metadata writer. Its methods write data\n    directly to disk.\n    \"\"\"\n\n    def __repr__(self):\n        return \"<{} DatasetWriter name='{}' mode='{}'>\".format(\n            self.closed and 'closed' or 'open', self.name, self.mode)\n\n\nclass BufferedDatasetWriter(BufferedDatasetWriterBase, WindowMethodsMixin,\n                            TransformMethodsMixin):\n    \"\"\"Maintains data and metadata in a buffer, writing to disk or\n    network only when `close()` is called.\n\n    This allows incremental updates to datasets using formats that don't\n    otherwise support updates, such as JPEG.\n    \"\"\"\n\n    def __repr__(self):\n        return \"<{} BufferedDatasetWriter name='{}' mode='{}'>\".format(\n            self.closed and 'closed' or 'open', self.name, self.mode)\n\n\nclass MemoryFile(MemoryFileBase):\n    \"\"\"A BytesIO-like object, backed by an in-memory file.\n\n    This allows formatted files to be read and written without I/O.\n\n    A MemoryFile created with initial bytes becomes immutable. A\n    MemoryFile created without initial bytes may be written to using\n    either file-like or dataset interfaces.\n\n    Examples\n    --------\n\n    A GeoTIFF can be loaded in memory and accessed using the GeoTIFF\n    format driver\n\n    >>> with open('tests/data/RGB.byte.tif', 'rb') as f, MemoryFile(f) as memfile:\n    ...     with memfile.open() as src:\n    ...         pprint.pprint(src.profile)\n    ...\n    {'count': 3,\n     'crs': CRS({'init': 'epsg:32618'}),\n     'driver': 'GTiff',\n     'dtype': 'uint8',\n     'height': 718,\n     'interleave': 'pixel',\n     'nodata': 0.0,\n     'tiled': False,\n     'transform': Affine(300.0379266750948, 0.0, 101985.0,\n           0.0, -300.041782729805, 2826915.0),\n     'width': 791}\n\n    \"\"\"\n    def __init__(self, file_or_bytes=None, filename=None, ext=''):\n        \"\"\"Create a new file in memory\n\n        Parameters\n        ----------\n        file_or_bytes : file-like object or bytes, optional\n            File or bytes holding initial data.\n        filename : str, optional\n            An optional filename. A unique one will otherwise be generated.\n        ext : str, optional\n            An optional extension.\n\n        Returns\n        -------\n        MemoryFile\n        \"\"\"\n        super(MemoryFile, self).__init__(\n            file_or_bytes=file_or_bytes, filename=filename, ext=ext)\n\n    @ensure_env\n    def open(self, driver=None, width=None, height=None, count=None, crs=None,\n             transform=None, dtype=None, nodata=None, sharing=False, **kwargs):\n        \"\"\"Open the file and return a Rasterio dataset object.\n\n        If data has already been written, the file is opened in 'r'\n        mode. Otherwise, the file is opened in 'w' mode.\n\n        Parameters\n        ----------\n        Note well that there is no `path` parameter: a `MemoryFile`\n        contains a single dataset and there is no need to specify a\n        path.\n\n        Other parameters are optional and have the same semantics as the\n        parameters of `rasterio.open()`.\n        \"\"\"\n        mempath = UnparsedPath(self.name)\n\n        if self.closed:\n            raise IOError(\"I/O operation on closed file.\")\n        if self.exists():\n            log.debug(\"VSI path: {}\".format(mempath.path))\n            return DatasetReader(mempath, driver=driver, sharing=sharing, **kwargs)\n        else:\n            writer = get_writer_for_driver(driver)\n            return writer(mempath, 'w+', driver=driver, width=width,\n                          height=height, count=count, crs=crs,\n                          transform=transform, dtype=dtype,\n                          nodata=nodata, sharing=sharing, **kwargs)\n\n    def __enter__(self):\n        self._env = env_ctx_if_needed()\n        self._env.__enter__()\n        return self\n\n    def __exit__(self, *args, **kwargs):\n        self._env.__exit__()\n        self.close()\n\n\nclass ZipMemoryFile(MemoryFile):\n    \"\"\"A read-only BytesIO-like object backed by an in-memory zip file.\n\n    This allows a zip file containing formatted files to be read\n    without I/O.\n    \"\"\"\n\n    def __init__(self, file_or_bytes=None):\n        super(ZipMemoryFile, self).__init__(file_or_bytes, ext='zip')\n\n    @ensure_env\n    def open(self, path, driver=None, sharing=False, **kwargs):\n        \"\"\"Open a dataset within the zipped stream.\n\n        Parameters\n        ----------\n        path : str\n            Path to a dataset in the zip file, relative to the root of the\n            archive.\n\n        Other parameters are optional and have the same semantics as the\n        parameters of `rasterio.open()`.\n\n        Returns\n        -------\n        A Rasterio dataset object\n        \"\"\"\n        zippath = UnparsedPath('/vsizip{0}/{1}'.format(self.name, path.lstrip('/')))\n\n        if self.closed:\n            raise IOError(\"I/O operation on closed file.\")\n        return DatasetReader(zippath, driver=driver, sharing=sharing, **kwargs)\n\n\ndef get_writer_for_driver(driver):\n    \"\"\"Return the writer class appropriate for the specified driver.\"\"\"\n    if not driver:\n        raise ValueError(\"'driver' is required to write dataset.\")\n    cls = None\n    if driver_can_create(driver):\n        cls = DatasetWriter\n    elif driver_can_create_copy(driver):  # pragma: no branch\n        cls = BufferedDatasetWriter\n    return cls\n\n\ndef get_writer_for_path(path, driver=None):\n    \"\"\"Return the writer class appropriate for the existing dataset.\"\"\"\n    if not driver:\n        driver = get_dataset_driver(path)\n    return get_writer_for_driver(driver)\n", "path": "rasterio/io.py"}], "after_files": [{"content": "\"\"\"Classes capable of reading and writing datasets\n\nInstances of these classes are called dataset objects.\n\"\"\"\n\nimport logging\n\nfrom rasterio._base import (\n    get_dataset_driver, driver_can_create, driver_can_create_copy)\nfrom rasterio._io import (\n    DatasetReaderBase, DatasetWriterBase, BufferedDatasetWriterBase,\n    MemoryFileBase)\nfrom rasterio.windows import WindowMethodsMixin\nfrom rasterio.env import ensure_env, env_ctx_if_needed\nfrom rasterio.transform import TransformMethodsMixin\nfrom rasterio.path import UnparsedPath\n\n\nlog = logging.getLogger(__name__)\n\n\nclass DatasetReader(DatasetReaderBase, WindowMethodsMixin,\n                    TransformMethodsMixin):\n    \"\"\"An unbuffered data and metadata reader\"\"\"\n\n    def __repr__(self):\n        return \"<{} DatasetReader name='{}' mode='{}'>\".format(\n            self.closed and 'closed' or 'open', self.name, self.mode)\n\n\nclass DatasetWriter(DatasetWriterBase, WindowMethodsMixin,\n                    TransformMethodsMixin):\n    \"\"\"An unbuffered data and metadata writer. Its methods write data\n    directly to disk.\n    \"\"\"\n\n    def __repr__(self):\n        return \"<{} DatasetWriter name='{}' mode='{}'>\".format(\n            self.closed and 'closed' or 'open', self.name, self.mode)\n\n\nclass BufferedDatasetWriter(BufferedDatasetWriterBase, WindowMethodsMixin,\n                            TransformMethodsMixin):\n    \"\"\"Maintains data and metadata in a buffer, writing to disk or\n    network only when `close()` is called.\n\n    This allows incremental updates to datasets using formats that don't\n    otherwise support updates, such as JPEG.\n    \"\"\"\n\n    def __repr__(self):\n        return \"<{} BufferedDatasetWriter name='{}' mode='{}'>\".format(\n            self.closed and 'closed' or 'open', self.name, self.mode)\n\n\nclass MemoryFile(MemoryFileBase):\n    \"\"\"A BytesIO-like object, backed by an in-memory file.\n\n    This allows formatted files to be read and written without I/O.\n\n    A MemoryFile created with initial bytes becomes immutable. A\n    MemoryFile created without initial bytes may be written to using\n    either file-like or dataset interfaces.\n\n    Examples\n    --------\n\n    A GeoTIFF can be loaded in memory and accessed using the GeoTIFF\n    format driver\n\n    >>> with open('tests/data/RGB.byte.tif', 'rb') as f, MemoryFile(f) as memfile:\n    ...     with memfile.open() as src:\n    ...         pprint.pprint(src.profile)\n    ...\n    {'count': 3,\n     'crs': CRS({'init': 'epsg:32618'}),\n     'driver': 'GTiff',\n     'dtype': 'uint8',\n     'height': 718,\n     'interleave': 'pixel',\n     'nodata': 0.0,\n     'tiled': False,\n     'transform': Affine(300.0379266750948, 0.0, 101985.0,\n           0.0, -300.041782729805, 2826915.0),\n     'width': 791}\n\n    \"\"\"\n    def __init__(self, file_or_bytes=None, dirname=None, filename=None, ext=''):\n        \"\"\"Create a new file in memory\n\n        Parameters\n        ----------\n        file_or_bytes : file-like object or bytes, optional\n            File or bytes holding initial data.\n        filename : str, optional\n            An optional filename. A unique one will otherwise be generated.\n        ext : str, optional\n            An optional extension.\n\n        Returns\n        -------\n        MemoryFile\n        \"\"\"\n        super(MemoryFile, self).__init__(\n            file_or_bytes=file_or_bytes, dirname=dirname, filename=filename, ext=ext)\n\n    @ensure_env\n    def open(self, driver=None, width=None, height=None, count=None, crs=None,\n             transform=None, dtype=None, nodata=None, sharing=False, **kwargs):\n        \"\"\"Open the file and return a Rasterio dataset object.\n\n        If data has already been written, the file is opened in 'r'\n        mode. Otherwise, the file is opened in 'w' mode.\n\n        Parameters\n        ----------\n        Note well that there is no `path` parameter: a `MemoryFile`\n        contains a single dataset and there is no need to specify a\n        path.\n\n        Other parameters are optional and have the same semantics as the\n        parameters of `rasterio.open()`.\n        \"\"\"\n        mempath = UnparsedPath(self.name)\n\n        if self.closed:\n            raise IOError(\"I/O operation on closed file.\")\n        if len(self) > 0:\n            log.debug(\"VSI path: {}\".format(mempath.path))\n            return DatasetReader(mempath, driver=driver, sharing=sharing, **kwargs)\n        else:\n            writer = get_writer_for_driver(driver)\n            return writer(mempath, 'w+', driver=driver, width=width,\n                          height=height, count=count, crs=crs,\n                          transform=transform, dtype=dtype,\n                          nodata=nodata, sharing=sharing, **kwargs)\n\n    def __enter__(self):\n        self._env = env_ctx_if_needed()\n        self._env.__enter__()\n        return self\n\n    def __exit__(self, *args, **kwargs):\n        self._env.__exit__()\n        self.close()\n\n\nclass ZipMemoryFile(MemoryFile):\n    \"\"\"A read-only BytesIO-like object backed by an in-memory zip file.\n\n    This allows a zip file containing formatted files to be read\n    without I/O.\n    \"\"\"\n\n    def __init__(self, file_or_bytes=None):\n        super(ZipMemoryFile, self).__init__(file_or_bytes, ext='zip')\n\n    @ensure_env\n    def open(self, path, driver=None, sharing=False, **kwargs):\n        \"\"\"Open a dataset within the zipped stream.\n\n        Parameters\n        ----------\n        path : str\n            Path to a dataset in the zip file, relative to the root of the\n            archive.\n\n        Other parameters are optional and have the same semantics as the\n        parameters of `rasterio.open()`.\n\n        Returns\n        -------\n        A Rasterio dataset object\n        \"\"\"\n        zippath = UnparsedPath('/vsizip{0}/{1}'.format(self.name, path.lstrip('/')))\n\n        if self.closed:\n            raise IOError(\"I/O operation on closed file.\")\n        return DatasetReader(zippath, driver=driver, sharing=sharing, **kwargs)\n\n\ndef get_writer_for_driver(driver):\n    \"\"\"Return the writer class appropriate for the specified driver.\"\"\"\n    if not driver:\n        raise ValueError(\"'driver' is required to write dataset.\")\n    cls = None\n    if driver_can_create(driver):\n        cls = DatasetWriter\n    elif driver_can_create_copy(driver):  # pragma: no branch\n        cls = BufferedDatasetWriter\n    return cls\n\n\ndef get_writer_for_path(path, driver=None):\n    \"\"\"Return the writer class appropriate for the existing dataset.\"\"\"\n    if not driver:\n        driver = get_dataset_driver(path)\n    return get_writer_for_driver(driver)\n", "path": "rasterio/io.py"}]}