diff --git a/applications/test/fileHandler-ranks1/Make/files b/applications/test/fileHandler-ranks1/Make/files
new file mode 100644
index 0000000000..7ad7a3eb9a
--- /dev/null
+++ b/applications/test/fileHandler-ranks1/Make/files
@@ -0,0 +1,3 @@
+Test-fileHandler-ranks1.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-fileHandler-ranks1
diff --git a/applications/test/fileHandler-ranks1/Make/options b/applications/test/fileHandler-ranks1/Make/options
new file mode 100644
index 0000000000..18e6fe47af
--- /dev/null
+++ b/applications/test/fileHandler-ranks1/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/fileHandler-ranks1/README b/applications/test/fileHandler-ranks1/README
new file mode 100644
index 0000000000..657fad446a
--- /dev/null
+++ b/applications/test/fileHandler-ranks1/README
@@ -0,0 +1,20 @@
+Test that -ioRanks selections perform as expected and that sub-rank
+selection is also doing the correct thing.
+
+For example,
+
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks host
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '(0 3 14)'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks 14,15,2,0,10,15,0,0,0,
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3,10'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3,11'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3,14'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3,15'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3,12,115'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3,10,12,115'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks host -pick '1,2,3,4'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -pick '2,4,6,8'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,3' -pick '2,4,6,8'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,4' -pick '2,4,6,8'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,6' -pick '2,4,6,8'
+mpirun -np 10 --oversubscribe Test-fileHandler-ranks1 -parallel -ioRanks '0,6' -pick '2,4,6,8'
diff --git a/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C b/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C
new file mode 100644
index 0000000000..253553e7d6
--- /dev/null
+++ b/applications/test/fileHandler-ranks1/Test-fileHandler-ranks1.C
@@ -0,0 +1,249 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2023 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Application
+ Test-fileHandler-ranks1
+
+Description
+ Test IO ranks and ranks selection
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "fileName.H"
+#include "fileOperation.H"
+#include "IOstreams.H"
+#include "ITstream.H"
+#include "OSspecific.H"
+#include "Pstream.H"
+#include "SHA1.H"
+#include "stringOps.H"
+
+using namespace Foam;
+
+// Parse space, comma, semicolon separated list of integers, floats etc...
+template
+static List splitStringToList(const std::string& str)
+{
+ const SubStrings items = stringOps::splitAny(str, " ,;");
+
+ DynamicList values(items.size());
+
+ for (const auto& item : items)
+ {
+ const std::string s(item.str());
+
+ PrimitiveType val;
+
+ if (Foam::read(s, val))
+ {
+ values.push_back(val);
+ }
+ else
+ {
+ // Report errors? Could get noisy...
+ }
+ }
+
+ return List(std::move(values));
+}
+
+
+//- Construct by parsing string for scalar ranges
+// The individual items are space, comma or semicolon delimited.
+static labelList parseIOranks
+(
+ const Foam::string& str,
+ label numProcs = -1
+)
+{
+ bool byHostName = false;
+
+ labelList ranks;
+
+ // Info<< "parsing: " << str << endl;
+
+ if (!str.empty())
+ {
+ if (str.contains('('))
+ {
+ // Looks like a list - tokenise it
+
+ ITstream is(str);
+ if (!is.empty())
+ {
+ is >> ranks;
+ }
+ }
+ else if (str == "host")
+ {
+ // Select by host
+ byHostName = true;
+ }
+ else
+ {
+ // Manual parse
+ ranks = splitStringToList