BUG: DataFrame.to_csv cannot return a binary string when not piped to file
### 

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the [latest version](https://pandas.pydata.org/docs/whatsnew/index.html) of pandas.

- [ ] I have confirmed this bug exists on the master branch of pandas.


### Reproducible Example

```python
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
print(df.to_csv(index=False))  # works
print(df.to_csv(mode="b", index=False))  # fails with unclear error
```


### Issue Description

When calling `to_csv` in binary mode without providing an output file, the following error is thrown:
```
  File "...\pandas\core\generic.py", line 3466, in to_csv
    return DataFrameRenderer(formatter).to_csv(
  File "...\pandas\io\formats\format.py", line 1105, in to_csv
    csv_formatter.save()
  File "...\pandas\io\formats\csvs.py", line 257, in save
    self._save()
  File "...\pandas\io\common.py", line 122, in __exit__
    self.close()
  File "...\pandas\io\common.py", line 107, in close
    self.handle.flush()
TypeError: string argument expected, got 'bytes'
```

I believe that is due to the use of `StringIO` as buffer [here](https://github.com/pandas-dev/pandas/blob/945c9ed766a61c7d2c0a7cbb251b6edebf9cb7d5/pandas/io/formats/format.py#L1082) (and possibly in other places) when the output is not directed to a file.

It is easy enough to work around on the user side (use the string output and do `unicodestring.encode()` on the result) but the error thrown is not very useful.

### Expected Behavior

In my view, from best to worse:

- Produce the expected binary string - in the example above `b'a,b\r\n1,4\r\n2,5\r\n3,6\r\n'`.
  - By replacing the StringIO buffer logic, see above.
  - By calling `.encode()` after formatting the string. Much simpler to code, but it might cause some memory issues if the output is large (doubling the output). Possibly some performance issues too?
- Raise a better exception. Even simpler to code, with something along the lines of
  ```
  if path_or_buf is None and "b" in mode:
      raise ValueError("Binary mode output can only be used for files. Produce a str and call .encode() afterwards.")
  ```
- Status quo


### Installed Versions

<details>

commit           : 945c9ed766a61c7d2c0a7cbb251b6edebf9cb7d5
python           : 3.9.6.final.0
python-bits      : 64
OS               : Windows
OS-release       : 10
Version          : 10.0.19043
machine          : AMD64
processor        : Intel64 Family 6 Model 140 Stepping 1, GenuineIntel
byteorder        : little
LC_ALL           : None
LANG             : fr_FR.UTF-8
LOCALE           : fr_FR.cp1252

pandas           : 1.3.4
numpy            : 1.20.2
pytz             : 2021.1
dateutil         : 2.8.1
pip              : 21.3.1
setuptools       : 56.0.0
Cython           : None
pytest           : None
hypothesis       : None
sphinx           : None
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : None
html5lib         : None
pymysql          : None
psycopg2         : 2.8.6 (dt dec pq3 ext lo64)
jinja2           : 2.11.3
IPython          : 7.26.0
pandas_datareader: None
bs4              : 4.9.3
bottleneck       : None
fsspec           : None
fastparquet      : None
gcsfs            : None
matplotlib       : 3.4.3
numexpr          : None
odfpy            : None
openpyxl         : 3.0.9
pandas_gbq       : None
pyarrow          : None
pyxlsb           : None
s3fs             : None
scipy            : 1.7.1
sqlalchemy       : 1.4.0
tables           : None
tabulate         : None
xarray           : None
xlrd             : 2.0.1
xlwt             : None
numba            : None

</details>
