diff --git a/respx/patterns.py b/respx/patterns.py
index 8d80148..da2022a 100644
--- a/respx/patterns.py
+++ b/respx/patterns.py
@@ -1,3 +1,4 @@
+import io
 import json as jsonlib
 import operator
 import pathlib
@@ -562,7 +563,7 @@ class Files(MultiItemsMixin, Pattern):
     key = "files"
     value: MultiItems
 
-    def _normalize_file_value(self, value: FileTypes) -> Tuple[Any, ...]:
+    def _normalize_file_value(self, value: FileTypes) -> Tuple[Any, Any]:
         # Mimic httpx `FileField` to normalize `files` kwarg to shortest tuple style
         if isinstance(value, tuple):
             filename, fileobj = value[:2]
@@ -573,6 +574,12 @@ class Files(MultiItemsMixin, Pattern):
                 filename = ANY
             fileobj = value
 
+        # Normalize file-like objects and strings to bytes to allow equality check
+        if isinstance(fileobj, io.BytesIO):
+            fileobj = fileobj.read()
+        elif isinstance(fileobj, str):
+            fileobj = fileobj.encode()
+
         return filename, fileobj
 
     def clean(self, value: RequestFiles) -> MultiItems:

diff --git a/tests/test_patterns.py b/tests/test_patterns.py
index 4b119aa..451b0dd 100644
--- a/tests/test_patterns.py
+++ b/tests/test_patterns.py
@@ -1,3 +1,4 @@
+import io
 import re
 from unittest.mock import ANY
 
@@ -456,6 +457,18 @@ def test_data_pattern(lookup, data, request_data, expected):
             },
             False,
         ),
+        (
+            Lookup.EQUAL,
+            {"file_1": ("filename.png", io.BytesIO(b"some..image..data"), "image/png")},
+            None,
+            True,
+        ),
+        (
+            Lookup.EQUAL,
+            {"file_1": ("filename.png", "some..image..data", "image/png")},  # str data
+            {"file_1": ("filename.png", io.BytesIO(b"some..image..data"), "image/png")},
+            True,
+        ),
         (
             Lookup.CONTAINS,
             {
@@ -487,6 +500,15 @@ def test_data_pattern(lookup, data, request_data, expected):
             },
             True,
         ),
+        (
+            Lookup.CONTAINS,
+            {"file_1": "foo..."},  # str data
+            {
+                "file_1": ("filename_1.txt", io.BytesIO(b"foo...")),
+                "file_2": ("filename_2.txt", io.BytesIO(b"bar...")),
+            },
+            True,
+        ),
         (
             Lookup.CONTAINS,
             [("file_1", b"ham...")],

`files` pattern not handling `str` and `io.BytesIO`
When using the `files` parameter in a helper (http) function, both `str` and `io.BytesIO` payloads are not deemed equal and raise an error.

# Input

## `str` payload
```py
@respx.mock
def test_file_str_payload():
    FILE_DATA = {"upload": ("image/png", "str", "image/png")}

    respx.patch("https://api.example.com/endpoint/123", files=FILE_DATA)

    httpx.patch("https://api.example.com/endpoint/123", files=FILE_DATA)

```

## `io.BytesIO` payload
```py
@respx.mock
def test_file_bytesio_payload():
    FILE_DATA = {
        "upload": ("image/png", io.BytesIO(b"some image content"), "image/png")
    }

    respx.patch("https://api.example.com/endpoint/123", files=FILE_DATA)

    httpx.patch("https://api.example.com/endpoint/123", files=FILE_DATA)
```

# Output

## Error raised
```bash
raise AllMockedAssertionError(f"RESPX: {request!r} not mocked!")
respx.models.AllMockedAssertionError: RESPX: <Request('PATCH', 'https://api.example.com/endpoint/123')> not mocked!
```
tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files7-None-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files8-request_files8-True] tests/test_patterns.py::test_files_pattern[Lookup.CONTAINS-files12-request_files12-True]
tests/test_patterns.py::test_bitwise_and tests/test_patterns.py::test_bitwise_operators[GET-https://foo.bar/-True] tests/test_patterns.py::test_bitwise_operators[GET-https://foo.bar/baz/-False] tests/test_patterns.py::test_bitwise_operators[POST-https://foo.bar/-True] tests/test_patterns.py::test_bitwise_operators[POST-https://ham.spam/-True] tests/test_patterns.py::test_bitwise_operators[PATCH-https://foo.bar/-True] tests/test_patterns.py::test_bitwise_operators[PUT-https://foo.bar/-False] tests/test_patterns.py::test_match_context tests/test_patterns.py::test_noop_pattern tests/test_patterns.py::test_m_pattern[kwargs0-https://foo.bar/-True] tests/test_patterns.py::test_m_pattern[kwargs1-https://foo.bar/?x=y-False] tests/test_patterns.py::test_m_pattern[kwargs2-https://foo.bar/?x=y-True] tests/test_patterns.py::test_method_pattern[Lookup.EQUAL-GET-True] tests/test_patterns.py::test_method_pattern[Lookup.EQUAL-get-True] tests/test_patterns.py::test_method_pattern[Lookup.EQUAL-POST-False] tests/test_patterns.py::test_method_pattern[Lookup.IN-value3-True] tests/test_patterns.py::test_method_pattern[Lookup.IN-value4-False] tests/test_patterns.py::test_headers_pattern[Lookup.CONTAINS-headers0-request_headers0-True] tests/test_patterns.py::test_headers_pattern[Lookup.CONTAINS-headers1--False] tests/test_patterns.py::test_headers_pattern_hash tests/test_patterns.py::test_cookies_pattern[Lookup.CONTAINS-cookies0-request_cookies0-True] tests/test_patterns.py::test_cookies_pattern[Lookup.CONTAINS-cookies1-request_cookies1-False] tests/test_patterns.py::test_cookies_pattern[Lookup.EQUAL-cookies2-request_cookies2-True] tests/test_patterns.py::test_cookies_pattern[Lookup.EQUAL-cookies3-request_cookies3-True] tests/test_patterns.py::test_cookies_pattern[Lookup.EQUAL-cookies4-request_cookies4-True] tests/test_patterns.py::test_cookies_pattern[Lookup.EQUAL-cookies5-None-True] tests/test_patterns.py::test_cookies_pattern[Lookup.EQUAL-cookies6-request_cookies6-False] tests/test_patterns.py::test_cookies_pattern__hash tests/test_patterns.py::test_scheme_pattern[Lookup.EQUAL-https-True] tests/test_patterns.py::test_scheme_pattern[Lookup.EQUAL-HTTPS-True] tests/test_patterns.py::test_scheme_pattern[Lookup.EQUAL-http-False] tests/test_patterns.py::test_scheme_pattern[Lookup.IN-scheme3-True] tests/test_patterns.py::test_host_pattern[Lookup.EQUAL-foo.bar-True] tests/test_patterns.py::test_host_pattern[Lookup.EQUAL-ham.spam-False] tests/test_patterns.py::test_host_pattern[Lookup.REGEX-.+\\.bar-True] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-443-https://foo.bar/-True] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-80-https://foo.bar/-False] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-80-http://foo.bar/-True] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-8080-https://foo.bar:8080/baz/-True] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-8080-https://foo.bar/baz/-False] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-22-//foo.bar:22/baz/-True] tests/test_patterns.py::test_port_pattern[Lookup.EQUAL-None-//foo.bar/-True] tests/test_patterns.py::test_port_pattern[Lookup.IN-port7-http://foo.bar/-True] tests/test_patterns.py::test_port_pattern[Lookup.IN-port8-https://foo.bar/-True] tests/test_patterns.py::test_port_pattern[Lookup.IN-port9-https://foo.bar:8080/-False] tests/test_patterns.py::test_path_pattern tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS--https://foo.bar/-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=1-https://foo.bar/?x=1-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=-https://foo.bar/?x=-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-y=2-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params5-https://foo.bar/?x=1-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params6-https://foo.bar/?x=1-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params7-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params8-https://foo.bar/?x=1&y=2-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params9-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params10-https://foo.bar/?x=1&x=2-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-params11-https://foo.bar/?x=2&x=3-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=1&y=2-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL--https://foo.bar/-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-x-https://foo.bar/?x-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-x=-https://foo.bar/?x=-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-x=1-https://foo.bar/?x=1-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-y=2-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-params18-https://foo.bar/?x=1-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-params19-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-params20-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-params21-https://foo.bar/-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-x=1&y=2-https://foo.bar/?x=1-False] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-y=2&x=1-https://foo.bar/?x=1&y=2-True] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-y=3&x=2&x=1-https://foo.bar/?x=1&x=2&y=3-False] tests/test_patterns.py::test_params_pattern[Lookup.EQUAL-y=3&x=1&x=2-https://foo.bar/?x=1&x=2&y=3-True] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=2&x=1-https://foo.bar/?x=1&x=2&y=3-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=1&x=2-https://foo.bar/?x=1&x=2&x=3-False] tests/test_patterns.py::test_params_pattern[Lookup.CONTAINS-x=1&x=2-https://foo.bar/?x=1&x=2&y=3-True] tests/test_patterns.py::test_params_pattern_hash tests/test_patterns.py::test_url_pattern[Lookup.REGEX-https?://a.b/(?P<c>\\w+)/-context0-http://a.b/c/-True] tests/test_patterns.py::test_url_pattern[Lookup.REGEX-^https://a.b/.+$-context1-https://a.b/c/-True] tests/test_patterns.py::test_url_pattern[Lookup.REGEX-https://a.b/c/-context2-https://x.y/c/-False] tests/test_patterns.py::test_url_pattern[Lookup.EQUAL-https://a.b/c/-context3-https://a.b/c/-True] tests/test_patterns.py::test_url_pattern[Lookup.EQUAL-https://a.b/x/-context4-https://a.b/c/-False] tests/test_patterns.py::test_url_pattern[Lookup.EQUAL-https://a.b?x=y-context5-https://a.b/?x=y-True] tests/test_patterns.py::test_url_pattern[Lookup.EQUAL-https://a.b/?x=y-context6-https://a.b?x=y-True] tests/test_patterns.py::test_url_pattern[Lookup.STARTS_WITH-https://a.b/b-context7-https://a.b/baz/-True] tests/test_patterns.py::test_url_pattern[Lookup.STARTS_WITH-http://a.b/baz/-context8-https://a.b/baz/-False] tests/test_patterns.py::test_url_pattern[Lookup.EQUAL-value9-context9-https://[FE80::1]-True] tests/test_patterns.py::test_url_pattern_invalid tests/test_patterns.py::test_url_pattern_hash tests/test_patterns.py::test_content_pattern[Lookup.EQUAL-foobar-True0] tests/test_patterns.py::test_content_pattern[Lookup.EQUAL-foobar-True1] tests/test_patterns.py::test_content_pattern[Lookup.CONTAINS-bar-True0] tests/test_patterns.py::test_content_pattern[Lookup.CONTAINS-bar-True1] tests/test_patterns.py::test_content_pattern[Lookup.CONTAINS-baz-False] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data0-None-True] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data1-request_data1-True] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data2-None-True] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data3-None-True] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data4-None-True] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data5-None-True] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data6-request_data6-False] tests/test_patterns.py::test_data_pattern[Lookup.EQUAL-data7-request_data7-False] tests/test_patterns.py::test_data_pattern[Lookup.CONTAINS-data8-request_data8-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files0-None-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files1-None-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files2-request_files2-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files3-None-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files4-request_files4-True] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files5-request_files5-False] tests/test_patterns.py::test_files_pattern[Lookup.EQUAL-files6-request_files6-False] tests/test_patterns.py::test_files_pattern[Lookup.CONTAINS-files9-request_files9-True] tests/test_patterns.py::test_files_pattern[Lookup.CONTAINS-files10-request_files10-True] tests/test_patterns.py::test_files_pattern[Lookup.CONTAINS-files11-request_files11-True] tests/test_patterns.py::test_files_pattern[Lookup.CONTAINS-files13-request_files13-False] tests/test_patterns.py::test_json_pattern[Lookup.EQUAL-value0-json0-True] tests/test_patterns.py::test_json_pattern[Lookup.EQUAL-value1-json1-False] tests/test_patterns.py::test_json_pattern[Lookup.EQUAL-value2-json2-True] tests/test_patterns.py::test_json_pattern[Lookup.EQUAL-value3-json3-False] tests/test_patterns.py::test_json_pattern[Lookup.EQUAL-json-string-json-string-True] tests/test_patterns.py::test_json_pattern_path[json0-foo__bar-baz-True] tests/test_patterns.py::test_json_pattern_path[json1-x-value1-True] tests/test_patterns.py::test_json_pattern_path[json2-ham__1__egg-yolk-True] tests/test_patterns.py::test_json_pattern_path[json3-0__name-jonas-True] tests/test_patterns.py::test_json_pattern_path[json4-pk-123-True] tests/test_patterns.py::test_json_pattern_path[json5-foo__ham-spam-False] tests/test_patterns.py::test_json_pattern_path[json6-1__name-lundberg-False] tests/test_patterns.py::test_invalid_pattern tests/test_patterns.py::test_iter_pattern tests/test_patterns.py::test_parse_url_patterns tests/test_patterns.py::test_merge_patterns tests/test_patterns.py::test_unique_pattern_key