diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst
index ac9f8b02c7acb..61848cb127029 100644
--- a/doc/source/whatsnew/v1.5.0.rst
+++ b/doc/source/whatsnew/v1.5.0.rst
@@ -819,6 +819,7 @@ I/O
- Bug in :func:`read_excel` when reading a ``.ods`` file with newlines between xml elements (:issue:`45598`)
- Bug in :func:`read_parquet` when ``engine="fastparquet"`` where the file was not closed on error (:issue:`46555`)
- :meth:`to_html` now excludes the ``border`` attribute from ``
`` elements when ``border`` keyword is set to ``False``.
+- Bug in :func:`read_sas` returned ``None`` rather than an empty DataFrame for SAS7BDAT files with zero rows (:issue:`18198`)
-
Period
diff --git a/pandas/io/sas/sas7bdat.py b/pandas/io/sas/sas7bdat.py
index debd686475432..1e071690d35fb 100644
--- a/pandas/io/sas/sas7bdat.py
+++ b/pandas/io/sas/sas7bdat.py
@@ -737,7 +737,7 @@ def read(self, nrows: int | None = None) -> DataFrame | None:
self.close()
raise EmptyDataError("No columns to parse from file")
- if self._current_row_in_file_index >= self.row_count:
+ if nrows > 0 and self._current_row_in_file_index >= self.row_count:
return None
m = self.row_count - self._current_row_in_file_index
diff --git a/pandas/tests/io/sas/data/zero_rows.sas7bdat b/pandas/tests/io/sas/data/zero_rows.sas7bdat
new file mode 100644
index 0000000000000..a5ba95b639507
Binary files /dev/null and b/pandas/tests/io/sas/data/zero_rows.sas7bdat differ
diff --git a/pandas/tests/io/sas/test_sas7bdat.py b/pandas/tests/io/sas/test_sas7bdat.py
index 0dd1fa175fa3f..2b3ccf57d3959 100644
--- a/pandas/tests/io/sas/test_sas7bdat.py
+++ b/pandas/tests/io/sas/test_sas7bdat.py
@@ -216,6 +216,14 @@ def test_zero_variables(datapath):
pd.read_sas(fname)
+def test_zero_rows(datapath):
+ # GH 18198
+ fname = datapath("io", "sas", "data", "zero_rows.sas7bdat")
+ result = pd.read_sas(fname)
+ expected = pd.DataFrame([{"char_field": "a", "num_field": 1.0}]).iloc[:0]
+ tm.assert_frame_equal(result, expected)
+
+
def test_corrupt_read(datapath):
# We don't really care about the exact failure, the important thing is
# that the resource should be cleaned up afterwards (BUG #35566)