diff --git a/src/OSspecific/POSIX/POSIX.C b/src/OSspecific/POSIX/POSIX.C
index 55fa68cbe93dabd1a000a42088132eaa12055fce..a63d3d746eee34e742e850e4e5e330d9080d00b4 100644
--- a/src/OSspecific/POSIX/POSIX.C
+++ b/src/OSspecific/POSIX/POSIX.C
@@ -87,44 +87,6 @@ static bool cwdPreference_(Foam::debug::optimisationSwitch("cwd", 0));
 
 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
 
-// Like fileName "/" global operator, but retain any invalid characters
-static inline Foam::fileName fileNameConcat
-(
-    const std::string& a,
-    const std::string& b
-)
-{
-    if (a.size())
-    {
-        if (b.size())
-        {
-            // Two non-empty strings: can concatenate
-
-            if (a.back() == '/' || b.front() == '/')
-            {
-                return Foam::fileName(a + b, false);
-            }
-            else
-            {
-                return Foam::fileName(a + '/' + b, false);
-            }
-        }
-
-        // The second string was empty
-        return Foam::fileName(a, false);
-    }
-
-    if (b.size())
-    {
-        // The first string is empty
-        return Foam::fileName(b, false);
-    }
-
-    // Both strings are empty
-    return Foam::fileName();
-}
-
-
 // After a fork in system(), before the exec() do the following
 // - close stdin when executing in background (daemon-like)
 // - redirect stdout to stderr when infoDetailLevel == 0
@@ -1273,7 +1235,7 @@ bool Foam::rmDir(const fileName& directory, const bool silent)
         // otherwise we cannot subdirs with these types of names.
         // -> const fileName path = directory/name; <-
 
-        const fileName path(fileNameConcat(directory, item));
+        const fileName path(fileName::concat(directory, item));
 
         if (path.type(false) == fileName::DIRECTORY)
         {
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.C b/src/OpenFOAM/primitives/strings/fileName/fileName.C
index c06a1d3d0595e94081ccf0b47a58804d45f9d3c4..f74c6877a68a228370cb217950d370e31cf4248d 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.C
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016-2018 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2016-2019 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
                             | Copyright (C) 2011-2017 OpenFOAM Foundation
@@ -56,7 +56,7 @@ Foam::fileName Foam::fileName::validate
     // but silently removes bad characters
 
     fileName out;
-    out.resize(s.size());
+    out.resize(s.length());
 
     std::string::size_type len = 0;
 
@@ -99,6 +99,33 @@ Foam::fileName Foam::fileName::validate
 }
 
 
+Foam::fileName Foam::fileName::concat
+(
+    const std::string& s1,
+    const std::string& s2
+)
+{
+    const auto n1 = s1.length();
+    const auto n2 = s2.length();
+
+    fileName out;
+    out.reserve(n1 + n2 + 1);
+
+    out += s1;
+
+    if (n1 && n2 && s1.back() != '/' && s2.front() != '/')
+    {
+        // Add separator
+        out += '/';
+    }
+
+    out += s2;
+
+    // Could also remove trailing '/', if desired.
+    return out;
+}
+
+
 bool Foam::fileName::equals(const std::string& s1, const std::string& s2)
 {
     // Do not use (s1 == s2) or s1.compare(s2) first since this would
@@ -107,8 +134,8 @@ bool Foam::fileName::equals(const std::string& s1, const std::string& s2)
     std::string::size_type i1 = 0;
     std::string::size_type i2 = 0;
 
-    const auto n1 = s1.size();
-    const auto n2 = s2.size();
+    const auto n1 = s1.length();
+    const auto n2 = s2.length();
 
     //Info<< "compare " << s1 << " == " << s2 << endl;
     while (i1 < n1 && i2 < n2)
@@ -264,7 +291,7 @@ bool Foam::fileName::clean(std::string& str)
     // Number of output characters
     auto nChar = top+1;
 
-    const auto maxLen = str.size();
+    const auto maxLen = str.length();
 
     for (auto src = nChar; src < maxLen; /*nil*/)
     {
@@ -477,7 +504,7 @@ Foam::fileName& Foam::fileName::operator/=(const string& other)
                 s += '/';
             }
 
-            s.append(other);
+            s += other;
         }
     }
     else if (other.size())
@@ -492,32 +519,32 @@ Foam::fileName& Foam::fileName::operator/=(const string& other)
 
 // * * * * * * * * * * * * * * * Global Operators  * * * * * * * * * * * * * //
 
-Foam::fileName Foam::operator/(const string& a, const string& b)
+Foam::fileName Foam::operator/(const string& s1, const string& s2)
 {
-    if (a.size())
+    if (s1.length())
     {
-        if (b.size())
+        if (s2.length())
         {
             // Two non-empty strings: can concatenate
 
-            if (a.back() == '/' || b.front() == '/')
+            if (s1.back() == '/' || s2.front() == '/')
             {
-                return fileName(a + b);
+                return fileName(s1 + s2);
             }
             else
             {
-                return fileName(a + '/' + b);
+                return fileName(s1 + '/' + s2);
             }
         }
 
         // The second string was empty
-        return a;
+        return s1;
     }
 
-    if (b.size())
+    if (s2.length())
     {
         // The first string is empty
-        return b;
+        return s2;
     }
 
     // Both strings are empty
diff --git a/src/OpenFOAM/primitives/strings/fileName/fileName.H b/src/OpenFOAM/primitives/strings/fileName/fileName.H
index b87d6a3b80c3dff6a4cb388efdd1c522ea16d5f6..a0c1570e75a5d675bc2406e33fa80b6a7efeaf2a 100644
--- a/src/OpenFOAM/primitives/strings/fileName/fileName.H
+++ b/src/OpenFOAM/primitives/strings/fileName/fileName.H
@@ -82,7 +82,7 @@ public:
     };
 
 
-    // Static data members
+    // Static Data Members
 
         //- The typeName
         static const char* const typeName;
@@ -149,6 +149,12 @@ public:
         //- removing duplicate or trailing slashes, etc.
         static fileName validate(const std::string& s, const bool doClean=true);
 
+        //- Join two strings with '/' as a path separator.
+        //  No '/' separator is added if either argument is an empty string or
+        //  if the arguments already had the path separator at the junction.
+        //  Invalid characters are \em not stripped (ie, retained).
+        static fileName concat(const std::string& s1, const std::string& s2);
+
         //- This is a specialized (possibly slower) version of compare()
         //- that ignores duplicate or trailing slashes.
         static bool equals(const std::string& s1, const std::string& s2);
@@ -402,7 +408,7 @@ Ostream& operator<<(Ostream& os, const fileName& val);
 
 //- Assemble words and fileNames as pathnames by adding a '/' separator.
 //  No '/' separator is added if either argument is an empty string.
-fileName operator/(const string& a, const string& b);
+fileName operator/(const string& s1, const string& s2);
 
 
 //- Recursively search the given directory for the file