diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt
index 6312c33aaf..946fd8faa5 100644
--- a/apps/bsatool/CMakeLists.txt
+++ b/apps/bsatool/CMakeLists.txt
@@ -10,6 +10,7 @@ openmw_add_executable(bsatool
 
 target_link_libraries(bsatool
   ${Boost_PROGRAM_OPTIONS_LIBRARY}
+  ${Boost_FILESYSTEM_LIBRARY}
   components
 )
 
diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp
index a8e28fcfb3..24c98fd139 100644
--- a/apps/bsatool/bsatool.cpp
+++ b/apps/bsatool/bsatool.cpp
@@ -1,10 +1,10 @@
-#include <filesystem>
-#include <fstream>
 #include <iostream>
 #include <iomanip>
 #include <vector>
 
 #include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 #include <components/bsa/compressedbsafile.hpp>
 #include <components/misc/stringops.hpp>
@@ -13,6 +13,7 @@
 
 // Create local aliases for brevity
 namespace bpo = boost::program_options;
+namespace bfs = boost::filesystem;
 
 struct Arguments
 {
@@ -200,26 +201,26 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
     }
 
     // Get the target path (the path the file will be extracted to)
-    std::filesystem::path relPath (extractPath);
-    std::filesystem::path outdir (info.outdir);
+    bfs::path relPath (extractPath);
+    bfs::path outdir (info.outdir);
 
-    std::filesystem::path target;
+    bfs::path target;
     if (info.fullpath)
         target = outdir / relPath;
     else
         target = outdir / relPath.filename();
 
     // Create the directory hierarchy
-    std::filesystem::create_directories(target.parent_path());
+    bfs::create_directories(target.parent_path());
 
-    std::filesystem::file_status s = std::filesystem::status(target.parent_path());
-    if (!std::filesystem::is_directory(s))
+    bfs::file_status s = bfs::status(target.parent_path());
+    if (!bfs::is_directory(s))
     {
         std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl;
         return 3;
     }
 
-    std::ofstream out(target, std::ios::binary);
+    bfs::ofstream out(target, std::ios::binary);
 
     // Write the file to disk
     std::cout << "Extracting " << info.extractfile << " to " << target << std::endl;
@@ -239,14 +240,14 @@ int extractAll(std::unique_ptr<File>& bsa, Arguments& info)
         Misc::StringUtils::replaceAll(extractPath, "\\", "/");
 
         // Get the target path (the path the file will be extracted to)
-        std::filesystem::path target (info.outdir);
+        bfs::path target (info.outdir);
         target /= extractPath;
 
         // Create the directory hierarchy
-        std::filesystem::create_directories(target.parent_path());
+        bfs::create_directories(target.parent_path());
 
-        std::filesystem::file_status s = std::filesystem::status(target.parent_path());
-        if (!std::filesystem::is_directory(s))
+        bfs::file_status s = bfs::status(target.parent_path());
+        if (!bfs::is_directory(s))
         {
             std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl;
             return 3;
@@ -254,7 +255,7 @@ int extractAll(std::unique_ptr<File>& bsa, Arguments& info)
 
         // Get a stream for the file to extract
         Files::IStreamPtr data = bsa->getFile(&file);
-        std::ofstream out(target, std::ios::binary);
+        bfs::ofstream out(target, std::ios::binary);
 
         // Write the file to disk
         std::cout << "Extracting " << target << std::endl;
@@ -268,7 +269,7 @@ int extractAll(std::unique_ptr<File>& bsa, Arguments& info)
 template<typename File>
 int add(std::unique_ptr<File>& bsa, Arguments& info)
 {
-    std::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
+    boost::filesystem::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
     bsa->addFile(info.addfile, stream);
 
     return 0;
diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp
index 9d90a542be..f2b998e3f2 100644
--- a/apps/esmtool/esmtool.cpp
+++ b/apps/esmtool/esmtool.cpp
@@ -4,12 +4,12 @@
 #include <list>
 #include <unordered_set>
 #include <map>
-#include <fstream>
 #include <cmath>
 #include <memory>
 #include <optional>
 #include <iomanip>
 
+#include <boost/filesystem/fstream.hpp>
 #include <boost/program_options.hpp>
 
 #include <components/esm3/esmreader.hpp>
@@ -308,7 +308,7 @@ void printRawTes3(std::string_view path)
     }
 }
 
-int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data)
+int loadTes3(const Arguments& info, std::unique_ptr<boost::filesystem::ifstream>&& stream, ESMData* data)
 {
     std::cout << "Loading TES3 file: " << info.filename << '\n';
 
@@ -499,7 +499,7 @@ int clone(const Arguments& info)
     esm.setVersion(ESM::VER_13);
     esm.setRecordCount (recordCount);
 
-    std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary);
+    boost::filesystem::fstream save(info.outname, boost::filesystem::fstream::out | boost::filesystem::fstream::binary);
     esm.save(save);
 
     int saved = 0;
diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp
index 3f213ff0b7..20329c3fdc 100644
--- a/apps/esmtool/tes4.cpp
+++ b/apps/esmtool/tes4.cpp
@@ -2,7 +2,6 @@
 #include "arguments.hpp"
 #include "labels.hpp"
 
-#include <fstream>
 #include <iostream>
 #include <type_traits>
 
@@ -286,7 +285,7 @@ namespace EsmTool
         }
     }
 
-    int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream)
+    int loadTes4(const Arguments& info, std::unique_ptr<boost::filesystem::ifstream>&& stream)
     {
         std::cout << "Loading TES4 file: " << info.filename << '\n';
 
diff --git a/apps/esmtool/tes4.hpp b/apps/esmtool/tes4.hpp
index 8149b26049..86546b8540 100644
--- a/apps/esmtool/tes4.hpp
+++ b/apps/esmtool/tes4.hpp
@@ -1,15 +1,16 @@
 #ifndef OPENMW_ESMTOOL_TES4_H
 #define OPENMW_ESMTOOL_TES4_H
 
-#include <fstream>
 #include <iosfwd>
 #include <memory>
 
+#include <boost/filesystem/fstream.hpp>
+
 namespace EsmTool
 {
     struct Arguments;
 
-    int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream);
+    int loadTes4(const Arguments& info, std::unique_ptr<boost::filesystem::ifstream>&& stream);
 }
 
 #endif
diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt
index 4d53bc4cb3..aa69b436f4 100644
--- a/apps/essimporter/CMakeLists.txt
+++ b/apps/essimporter/CMakeLists.txt
@@ -35,6 +35,7 @@ openmw_add_executable(openmw-essimporter
 
 target_link_libraries(openmw-essimporter
     ${Boost_PROGRAM_OPTIONS_LIBRARY}
+    ${Boost_FILESYSTEM_LIBRARY}
     components
 )
 
diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp
index f0c74a7333..7539633d5a 100644
--- a/apps/essimporter/importer.cpp
+++ b/apps/essimporter/importer.cpp
@@ -1,8 +1,8 @@
 #include "importer.hpp"
 
 #include <iomanip>
-#include <filesystem>
-#include <fstream>
+
+#include <boost/filesystem/fstream.hpp>
 
 #include <osgDB/ReadFile>
 #include <osg/ImageUtils>
@@ -345,7 +345,7 @@ namespace ESSImport
 
         writer.setFormat (ESM::SavedGame::sCurrentFormat);
 
-        std::ofstream stream(std::filesystem::path(mOutFile), std::ios::out | std::ios::binary);
+        boost::filesystem::ofstream stream(boost::filesystem::path(mOutFile), std::ios::out | std::ios::binary);
         // all unused
         writer.setVersion(0);
         writer.setType(0);
diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp
index 9517df2d2a..bc5d34bc03 100644
--- a/apps/essimporter/main.cpp
+++ b/apps/essimporter/main.cpp
@@ -1,13 +1,14 @@
 #include <iostream>
-#include <filesystem>
 
 #include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
 
 #include <components/files/configurationmanager.hpp>
 
 #include "importer.hpp"
 
 namespace bpo = boost::program_options;
+namespace bfs = boost::filesystem;
 
 
 int main(int argc, char** argv)
@@ -56,7 +57,7 @@ int main(int argc, char** argv)
         else
         {
             const std::string& ext = ".omwsave";
-            if (std::filesystem::exists(std::filesystem::path(outputFile))
+            if (bfs::exists(bfs::path(outputFile))
                     && (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext))
             {
                 throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?");
diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp
index a40a4770bf..13e05cb200 100644
--- a/apps/navmeshtool/main.cpp
+++ b/apps/navmeshtool/main.cpp
@@ -26,6 +26,7 @@
 
 #include <osg/Vec3f>
 
+#include <boost/filesystem.hpp>
 #include <boost/program_options.hpp>
 
 #include <cstddef>
diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt
index 2f0dcb59e3..9ae0149295 100644
--- a/apps/niftest/CMakeLists.txt
+++ b/apps/niftest/CMakeLists.txt
@@ -9,6 +9,7 @@ openmw_add_executable(niftest
 )
 
 target_link_libraries(niftest
+  ${Boost_FILESYSTEM_LIBRARY}
   components
 )
 
diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp
index 219956cd75..22cb695169 100644
--- a/apps/niftest/niftest.cpp
+++ b/apps/niftest/niftest.cpp
@@ -1,7 +1,6 @@
 ///Program to test .nif files both on the FileSystem and in BSA archives.
 
 #include <iostream>
-#include <filesystem>
 
 #include <components/misc/stringops.hpp>
 #include <components/nif/niffile.hpp>
@@ -11,9 +10,11 @@
 #include <components/vfs/filesystemarchive.hpp>
 
 #include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
 
 // Create local aliases for brevity
 namespace bpo = boost::program_options;
+namespace bfs = boost::filesystem;
 
 ///See if the file has the named extension
 bool hasExtension(std::string filename, std::string extensionToFind)
@@ -136,7 +137,7 @@ int main(int argc, char **argv)
 //                 std::cout << "Reading BSA File: " << name << std::endl;
                 readVFS(std::make_unique<VFS::BsaArchive>(name));
              }
-             else if(std::filesystem::is_directory(std::filesystem::path(name)))
+             else if(bfs::is_directory(bfs::path(name)))
              {
 //                 std::cout << "Reading All Files in: " << name << std::endl;
                 readVFS(std::make_unique<VFS::FileSystemArchive>(name), name);
diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp
index 727352a872..bc40219a6a 100644
--- a/apps/opencs/model/doc/savingstate.hpp
+++ b/apps/opencs/model/doc/savingstate.hpp
@@ -1,7 +1,6 @@
 #ifndef CSM_DOC_SAVINGSTATE_H
 #define CSM_DOC_SAVINGSTATE_H
 
-#include <fstream>
 #include <map>
 #include <deque>
 
diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp
index d0a3afc361..0bfe71c1e9 100644
--- a/apps/openmw/engine.cpp
+++ b/apps/openmw/engine.cpp
@@ -3,7 +3,6 @@
 #include <iomanip>
 #include <chrono>
 #include <thread>
-#include <filesystem>
 
 #include <boost/filesystem/fstream.hpp>
 
@@ -712,7 +711,7 @@ void OMW::Engine::createWindow()
 
 void OMW::Engine::setWindowIcon()
 {
-    std::ifstream windowIconStream;
+    boost::filesystem::ifstream windowIconStream;
     std::string windowIcon = (mResDir / "openmw.png").string();
     windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
     if (windowIconStream.fail())
@@ -789,13 +788,13 @@ void OMW::Engine::prepareEngine()
     // showing a loading screen and keeping the window responsive while doing so
 
     std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string();
-    bool keybinderUserExists = std::filesystem::exists(keybinderUser);
+    bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
     if(!keybinderUserExists)
     {
         std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string();
-        if(std::filesystem::exists(input2)) {
-            std::filesystem::copy_file(input2, keybinderUser);
-            keybinderUserExists = std::filesystem::exists(keybinderUser);
+        if(boost::filesystem::exists(input2)) {
+            boost::filesystem::copy_file(input2, keybinderUser);
+            keybinderUserExists = boost::filesystem::exists(keybinderUser);
             Log(Debug::Info) << "Loading keybindings file: " << keybinderUser;
         }
     }
@@ -807,13 +806,13 @@ void OMW::Engine::prepareEngine()
     const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.txt";
 
     std::string userGameControllerdb;
-    if (std::filesystem::exists(userdefault))
+    if (boost::filesystem::exists(userdefault))
         userGameControllerdb = userdefault;
 
     std::string gameControllerdb;
-    if (std::filesystem::exists(localdefault))
+    if (boost::filesystem::exists(localdefault))
         gameControllerdb = localdefault;
-    else if (std::filesystem::exists(globaldefault))
+    else if (boost::filesystem::exists(globaldefault))
         gameControllerdb = globaldefault;
     //else if it doesn't exist, pass in an empty string
 
@@ -1037,7 +1036,7 @@ void OMW::Engine::go()
 
     prepareEngine();
 
-    std::ofstream stats;
+    boost::filesystem::ofstream stats;
     if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE"))
     {
         stats.open(path, std::ios_base::out);
diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index f13d1b39b5..a826b11b89 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -21,8 +21,6 @@
 extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
 #endif
 
-#include <filesystem>
-
 #if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix))
 #include <unistd.h>
 #endif
@@ -214,8 +212,8 @@ int runApplication(int argc, char *argv[])
     Platform::init();
 
 #ifdef __APPLE__
-    std::filesystem::path binary_path = std::filesystem::absolute(std::filesystem::path(argv[0]));
-    std::filesystem::current_path(binary_path.parent_path());
+    boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
+    boost::filesystem::current_path(binary_path.parent_path());
     setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
 #endif
 
diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp
index a382bbeb07..aaf36aab59 100644
--- a/apps/openmw/mwgui/console.cpp
+++ b/apps/openmw/mwgui/console.cpp
@@ -4,8 +4,8 @@
 #include <MyGUI_InputManager.h>
 #include <MyGUI_LayerManager.h>
 
-#include <filesystem>
-#include <fstream>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 #include <components/compiler/exception.hpp>
 #include <components/compiler/extensions0.hpp>
@@ -220,7 +220,8 @@ namespace MWGui
 
     void Console::executeFile (const std::string& path)
     {
-        std::ifstream stream ((std::filesystem::path(path)));
+        namespace bfs = boost::filesystem;
+        bfs::ifstream stream ((bfs::path(path)));
 
         if (!stream.is_open())
             printError ("failed to open file: " + path);
diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp
index b78276b259..17d082b013 100644
--- a/apps/openmw/mwgui/windowmanagerimp.cpp
+++ b/apps/openmw/mwgui/windowmanagerimp.cpp
@@ -3,7 +3,6 @@
 #include <algorithm>
 #include <cassert>
 #include <chrono>
-#include <filesystem>
 #include <thread>
 
 #include <osgViewer/Viewer>
@@ -196,7 +195,7 @@ namespace MWGui
         mScalingFactor = std::clamp(Settings::Manager::getFloat("scaling factor", "GUI"), 0.5f, 8.f);
         mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(),
             resourceSystem->getVFS(), mScalingFactor, "mygui",
-            (std::filesystem::path(logpath) / "MyGUI.log").generic_string());
+            (boost::filesystem::path(logpath) / "MyGUI.log").generic_string());
 
         mGui = new MyGUI::Gui;
         mGui->initialise("");
diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp
index fba78e47de..dd21517669 100644
--- a/apps/openmw/mwlua/luamanagerimp.cpp
+++ b/apps/openmw/mwlua/luamanagerimp.cpp
@@ -1,7 +1,5 @@
 #include "luamanagerimp.hpp"
 
-#include <filesystem>
-
 #include <components/debug/debuglog.hpp>
 
 #include <components/esm3/esmreader.hpp>
@@ -111,19 +109,19 @@ namespace MWLua
 
     void LuaManager::loadPermanentStorage(const std::string& userConfigPath)
     {
-        auto globalPath = std::filesystem::path(userConfigPath) / "global_storage.bin";
-        auto playerPath = std::filesystem::path(userConfigPath) / "player_storage.bin";
-        if (std::filesystem::exists(globalPath))
-            mGlobalStorage.load(globalPath.string());
-        if (std::filesystem::exists(playerPath))
-            mPlayerStorage.load(playerPath.string());
+        auto globalPath = boost::filesystem::path(userConfigPath) / "global_storage.bin";
+        auto playerPath = boost::filesystem::path(userConfigPath) / "player_storage.bin";
+        if (boost::filesystem::exists(globalPath))
+            mGlobalStorage.load(globalPath);
+        if (boost::filesystem::exists(playerPath))
+            mPlayerStorage.load(playerPath);
     }
 
     void LuaManager::savePermanentStorage(const std::string& userConfigPath)
     {
-        std::filesystem::path confDir(userConfigPath);
-        mGlobalStorage.save((confDir / "global_storage.bin").string());
-        mPlayerStorage.save((confDir / "player_storage.bin").string());
+        boost::filesystem::path confDir(userConfigPath);
+        mGlobalStorage.save((confDir / "global_storage.bin"));
+        mPlayerStorage.save((confDir / "player_storage.bin"));
     }
 
     void LuaManager::update()
diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp
index eec8a6b969..6e7af2c305 100644
--- a/apps/openmw/mwrender/postprocessor.cpp
+++ b/apps/openmw/mwrender/postprocessor.cpp
@@ -11,6 +11,8 @@
 #include <osg/Texture3D>
 #include <osg/Texture2DArray>
 
+#include <boost/filesystem/operations.hpp>
+
 #include <components/settings/settings.hpp>
 #include <components/sceneutil/depth.hpp>
 #include <components/sceneutil/color.hpp>
@@ -216,11 +218,11 @@ namespace MWRender
     {
         for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
         {
-            std::filesystem::path path = name;
+            boost::filesystem::path path = name;
             std::string fileExt = Misc::StringUtils::lowerCase(path.extension().string());
             if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt)
             {
-                auto absolutePath = std::filesystem::path(mVFS->getAbsoluteFileName(name));
+                auto absolutePath = boost::filesystem::path(mVFS->getAbsoluteFileName(name));
                 mTechniqueFileMap[absolutePath.stem().string()] = absolutePath;
             }
         }
@@ -375,7 +377,7 @@ namespace MWRender
             if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
                 continue;
 
-            const auto lastWriteTime = std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]);
+            const auto lastWriteTime = boost::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]);
             const bool isDirty = technique->setLastModificationTime(lastWriteTime);
 
             if (!isDirty)
@@ -788,7 +790,7 @@ namespace MWRender
         technique->compile();
 
         if (technique->getStatus() != fx::Technique::Status::File_Not_exists)
-            technique->setLastModificationTime(std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]));
+            technique->setLastModificationTime(boost::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]));
 
         if (loadNextFrame)
         {
diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp
index 23cd0f130b..4d8a6cd158 100644
--- a/apps/openmw/mwrender/postprocessor.hpp
+++ b/apps/openmw/mwrender/postprocessor.hpp
@@ -6,8 +6,6 @@
 #include <string>
 #include <unordered_map>
 
-#include <filesystem>
-
 #include <osg/Texture2D>
 #include <osg/Group>
 #include <osg/FrameBufferObject>
@@ -220,7 +218,7 @@ namespace MWRender
         TechniqueList mTemplates;
         TechniqueList mQueuedTemplates;
 
-        std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
+        std::unordered_map<std::string, boost::filesystem::path> mTechniqueFileMap;
 
         int mSamples;
 
diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp
index 41fbc1c05b..dd598e456f 100644
--- a/apps/openmw/mwrender/water.cpp
+++ b/apps/openmw/mwrender/water.cpp
@@ -14,7 +14,8 @@
 
 #include <osgDB/ReadFile>
 
-#include <fstream>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 #include <osgUtil/IncrementalCompileOperation>
 #include <osgUtil/CullVisitor>
@@ -241,7 +242,8 @@ private:
 
 osg::ref_ptr<osg::Image> readPngImage (const std::string& file)
 {
-    std::ifstream inStream;
+    // use boost in favor of osgDB::readImage, to handle utf-8 path issues on Windows
+    boost::filesystem::ifstream inStream;
     inStream.open(file, std::ios_base::in | std::ios_base::binary);
     if (inStream.fail())
         Log(Debug::Error) << "Error: Failed to open " << file;
diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp
index 9f572fde9e..a59ef465ff 100644
--- a/apps/openmw/mwstate/statemanagerimp.cpp
+++ b/apps/openmw/mwstate/statemanagerimp.cpp
@@ -1,6 +1,6 @@
 #include "statemanagerimp.hpp"
 
-#include <filesystem>
+#include <chrono>
 
 #include <components/debug/debuglog.hpp>
 
@@ -390,7 +390,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
     {
         cleanup();
 
-        Log(Debug::Info) << "Reading save file " << std::filesystem::path(filepath).filename().string();
+        Log(Debug::Info) << "Reading save file " << boost::filesystem::path(filepath).filename().string();
 
         ESM::ESMReader reader;
         reader.open (filepath);
diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp
index 2c9b374645..5e7e3f8220 100644
--- a/apps/openmw/mwworld/esmstore.cpp
+++ b/apps/openmw/mwworld/esmstore.cpp
@@ -1,7 +1,8 @@
 #include "esmstore.hpp"
 
 #include <algorithm>
-#include <fstream>
+
+#include <boost/filesystem/fstream.hpp>
 
 #include <components/debug/debuglog.hpp>
 #include <components/esm3/esmreader.hpp>
@@ -229,7 +230,7 @@ ESM::LuaScriptsCfg ESMStore::getLuaScriptsCfg() const
             // It is important for the `reloadlua` console command.
             try
             {
-                auto file = std::ifstream(std::get<std::string>(c));
+                auto file = boost::filesystem::ifstream(std::get<std::string>(c));
                 std::string fileContent(std::istreambuf_iterator<char>(file), {});
                 LuaUtil::parseOMWScripts(cfg, fileContent);
             }
diff --git a/apps/openmw_test_suite/files/hash.cpp b/apps/openmw_test_suite/files/hash.cpp
index f8303ac1f3..cae1039ed5 100644
--- a/apps/openmw_test_suite/files/hash.cpp
+++ b/apps/openmw_test_suite/files/hash.cpp
@@ -4,8 +4,9 @@
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
 
+#include <boost/filesystem/fstream.hpp>
+
 #include <algorithm>
-#include <fstream>
 #include <sstream>
 #include <string>
 
@@ -51,7 +52,7 @@ namespace
         std::string content;
         std::fill_n(std::back_inserter(content), GetParam().mSize, 'a');
         fileName = outputFilePath(fileName);
-        std::fstream(fileName, std::ios_base::out | std::ios_base::binary)
+        boost::filesystem::fstream(fileName, boost::filesystem::fstream::out | boost::filesystem::fstream::binary)
             .write(content.data(), static_cast<std::streamsize>(content.size()));
         const auto stream = Files::openConstrainedFileStream(fileName, 0, content.size());
         EXPECT_EQ(getHash(fileName, *stream), GetParam().mHash);
diff --git a/apps/openmw_test_suite/lua/test_configuration.cpp b/apps/openmw_test_suite/lua/test_configuration.cpp
index 39c4f06201..8f952684a2 100644
--- a/apps/openmw_test_suite/lua/test_configuration.cpp
+++ b/apps/openmw_test_suite/lua/test_configuration.cpp
@@ -1,7 +1,7 @@
 #include "gmock/gmock.h"
 #include <gtest/gtest.h>
 
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 #include <components/esm3/esmreader.hpp>
 #include <components/esm3/esmwriter.hpp>
@@ -182,7 +182,7 @@ namespace
 
         {
             // Save for manual testing.
-            std::ofstream f(TestingOpenMW::outputFilePath("lua_conf_test.omwaddon"), std::ios::binary);
+            boost::filesystem::ofstream f(TestingOpenMW::outputFilePath("lua_conf_test.omwaddon"), boost::filesystem::fstream::binary);
             f << serializedOMWAddon;
             f.close();
         }
diff --git a/apps/openmw_test_suite/lua/test_storage.cpp b/apps/openmw_test_suite/lua/test_storage.cpp
index c1d8cc4c4f..e4c80e239c 100644
--- a/apps/openmw_test_suite/lua/test_storage.cpp
+++ b/apps/openmw_test_suite/lua/test_storage.cpp
@@ -1,7 +1,9 @@
-#include <filesystem>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
 #include <components/lua/scriptscontainer.hpp>
 #include <components/lua/storage.hpp>
 
@@ -88,7 +90,7 @@ namespace
         mLua.safe_script("permanent:set('x', 1)");
         mLua.safe_script("temporary:set('y', 2)");
 
-        std::string tmpFile = (std::filesystem::temp_directory_path() / "test_storage.bin").string();
+        std::string tmpFile = (boost::filesystem::temp_directory_path() / "test_storage.bin").string();
         storage.save(tmpFile);
         EXPECT_EQ(get<int>(mLua, "permanent:get('x')"), 1);
         EXPECT_EQ(get<int>(mLua, "temporary:get('y')"), 2);
diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp
index 34079a8172..9a8aa66828 100644
--- a/apps/openmw_test_suite/mwworld/test_store.cpp
+++ b/apps/openmw_test_suite/mwworld/test_store.cpp
@@ -1,6 +1,6 @@
 #include <gtest/gtest.h>
 
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 #include <boost/program_options/options_description.hpp>
 #include <boost/program_options/variables_map.hpp>
@@ -109,7 +109,8 @@ TEST_F(ContentFileTest, dialogue_merging_test)
     }
 
     const std::string file = TestingOpenMW::outputFilePath("test_dialogue_merging.txt");
-    std::ofstream stream(file);
+    boost::filesystem::ofstream stream;
+    stream.open(file);
 
     const MWWorld::Store<ESM::Dialogue>& dialStore = mEsmStore.get<ESM::Dialogue>();
     for (const auto & dial : dialStore)
@@ -189,7 +190,8 @@ TEST_F(ContentFileTest, content_diagnostics_test)
     }
 
     const std::string file = TestingOpenMW::outputFilePath("test_content_diagnostics.txt");
-    std::ofstream stream(file);
+    boost::filesystem::ofstream stream;
+    stream.open(file);
 
     RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream);
 
diff --git a/apps/openmw_test_suite/settings/parser.cpp b/apps/openmw_test_suite/settings/parser.cpp
index 7e250b43aa..bf435afeae 100644
--- a/apps/openmw_test_suite/settings/parser.cpp
+++ b/apps/openmw_test_suite/settings/parser.cpp
@@ -1,6 +1,6 @@
 #include <components/settings/parser.hpp>
 
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 #include <gtest/gtest.h>
 
@@ -23,7 +23,7 @@ namespace
                 std::string(UnitTest::GetInstance()->current_test_info()->name()) + ".cfg");
 
             {
-                std::ofstream stream(path);
+                boost::filesystem::ofstream stream(path);
                 stream << content;
                 stream.close();
             }
diff --git a/apps/openmw_test_suite/settings/shadermanager.cpp b/apps/openmw_test_suite/settings/shadermanager.cpp
index e4f40aaa03..f479582b43 100644
--- a/apps/openmw_test_suite/settings/shadermanager.cpp
+++ b/apps/openmw_test_suite/settings/shadermanager.cpp
@@ -1,7 +1,6 @@
 #include <components/settings/shadermanager.hpp>
 
-#include <filesystem>
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 #include <gtest/gtest.h>
 
@@ -21,7 +20,7 @@ namespace
                 std::string(UnitTest::GetInstance()->current_test_info()->name()) + ".yaml");
 
             {
-                std::ofstream stream;
+                boost::filesystem::ofstream stream;
                 stream.open(path);
                 stream << content;
                 stream.close();
@@ -69,4 +68,4 @@ config:
             EXPECT_FALSE(ShaderManager::get().save());
         });
     }
-}
\ No newline at end of file
+}
diff --git a/apps/openmw_test_suite/shader/shadermanager.cpp b/apps/openmw_test_suite/shader/shadermanager.cpp
index 58ca3b6f3f..1605258cbd 100644
--- a/apps/openmw_test_suite/shader/shadermanager.cpp
+++ b/apps/openmw_test_suite/shader/shadermanager.cpp
@@ -1,6 +1,6 @@
 #include <components/shader/shadermanager.hpp>
 
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 #include <gtest/gtest.h>
 
@@ -34,7 +34,7 @@ namespace
                 std::string(UnitTest::GetInstance()->current_test_info()->name()) + suffix + ".glsl");
 
             {
-                std::ofstream stream(path);
+                boost::filesystem::ofstream stream(path);
                 stream << content;
                 stream.close();
             }
diff --git a/apps/openmw_test_suite/testing_util.hpp b/apps/openmw_test_suite/testing_util.hpp
index 125d2505ed..e314bf306d 100644
--- a/apps/openmw_test_suite/testing_util.hpp
+++ b/apps/openmw_test_suite/testing_util.hpp
@@ -1,9 +1,11 @@
 #ifndef TESTING_UTIL_H
 #define TESTING_UTIL_H
 
-#include <filesystem>
 #include <sstream>
 
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
 #include <components/vfs/archive.hpp>
 #include <components/vfs/manager.hpp>
 
@@ -12,14 +14,14 @@ namespace TestingOpenMW
 
     inline std::string outputFilePath(const std::string name)
     {
-        std::filesystem::path dir("tests_output");
-        std::filesystem::create_directory(dir);
+        boost::filesystem::path dir("tests_output");
+        boost::filesystem::create_directory(dir);
         return (dir / name).string();
     }
 
     inline std::string temporaryFilePath(const std::string name)
     {
-        return (std::filesystem::temp_directory_path() / name).string();
+        return (boost::filesystem::temp_directory_path() / name).string();
     }
 
     class VFSTestFile : public VFS::File
diff --git a/apps/openmw_test_suite/toutf8/toutf8.cpp b/apps/openmw_test_suite/toutf8/toutf8.cpp
index d1cf6b2851..86ba678cd3 100644
--- a/apps/openmw_test_suite/toutf8/toutf8.cpp
+++ b/apps/openmw_test_suite/toutf8/toutf8.cpp
@@ -2,7 +2,7 @@
 
 #include <gtest/gtest.h>
 
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 #ifndef OPENMW_TEST_SUITE_SOURCE_DIR
 #define OPENMW_TEST_SUITE_SOURCE_DIR ""
@@ -22,8 +22,8 @@ namespace
 
     std::string readContent(const std::string& fileName)
     {
-        std::ifstream file;
-        file.exceptions(std::ios::failbit | std::ios::badbit);
+        boost::filesystem::ifstream file;
+        file.exceptions(boost::filesystem::fstream::failbit | boost::filesystem::fstream::badbit);
         file.open(std::string(OPENMW_TEST_SUITE_SOURCE_DIR) + "/toutf8/data/" + fileName);
         std::stringstream buffer;
         buffer << file.rdbuf();
diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp
index 9fc6448c2b..4f795ec0d4 100644
--- a/components/bsa/bsa_file.cpp
+++ b/components/bsa/bsa_file.cpp
@@ -25,11 +25,11 @@
 
 #include <components/files/constrainedfilestream.hpp>
 
-#include <algorithm>
 #include <cassert>
-#include <cstring>
-#include <filesystem>
-#include <fstream>
+
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
 
 using namespace Bsa;
 
@@ -100,7 +100,8 @@ void BSAFile::readHeader()
      */
     assert(!mIsLoaded);
 
-    std::ifstream input(std::filesystem::path(mFilename), std::ios_base::binary);
+    namespace bfs = boost::filesystem;
+    bfs::ifstream input(bfs::path(mFilename), std::ios_base::binary);
 
     // Total archive size
     std::streamoff fsize = 0;
@@ -196,7 +197,8 @@ void BSAFile::readHeader()
 /// Write header information to the output sink
 void Bsa::BSAFile::writeHeader()
 {
-    std::fstream output(mFilename, std::ios::binary | std::ios::in | std::ios::out);
+    namespace bfs = boost::filesystem;
+    bfs::fstream output(mFilename, std::ios::binary | std::ios::in | std::ios::out);
 
     uint32_t head[3];
     head[0] = 0x100;
@@ -237,11 +239,11 @@ void BSAFile::open(const std::string &file)
         close();
 
     mFilename = file;
-    if(std::filesystem::exists(file))
+    if(boost::filesystem::exists(file))
         readHeader();
     else
     {
-        { std::fstream(mFilename, std::ios::binary | std::ios::out); }
+        { boost::filesystem::fstream(mFilename, std::ios::binary | std::ios::out); }
         writeHeader();
         mIsLoaded = true;
     }
@@ -267,12 +269,13 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file)
 {
     if (!mIsLoaded)
         fail("Unable to add file " + filename + " the archive is not opened");
+    namespace bfs = boost::filesystem;
 
     auto newStartOfDataBuffer = 12 + (12 + 8) * (mFiles.size() + 1) + mStringBuf.size() + filename.size() + 1;
     if (mFiles.empty())
-        std::filesystem::resize_file(mFilename, newStartOfDataBuffer);
+        bfs::resize_file(mFilename, newStartOfDataBuffer);
 
-    std::fstream stream(mFilename, std::ios::binary | std::ios::in | std::ios::out);
+    bfs::fstream stream(mFilename, std::ios::binary | std::ios::in | std::ios::out);
 
     FileStruct newFile;
     file.seekg(0, std::ios::end);
diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp
index 67e172e3db..436fc01f14 100644
--- a/components/bsa/compressedbsafile.cpp
+++ b/components/bsa/compressedbsafile.cpp
@@ -26,11 +26,11 @@
 
 #include <stdexcept>
 #include <cassert>
-#include <filesystem>
-#include <fstream>
 
 #include <lz4frame.h>
 
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 #include <boost/iostreams/filtering_streambuf.hpp>
 #include <boost/iostreams/copy.hpp>
@@ -119,7 +119,8 @@ void CompressedBSAFile::readHeader()
 {
     assert(!mIsLoaded);
 
-    std::ifstream input(std::filesystem::path(mFilename), std::ios_base::binary);
+    namespace bfs = boost::filesystem;
+    bfs::ifstream input(bfs::path(mFilename), std::ios_base::binary);
 
     // Total archive size
     std::streamoff fsize = 0;
@@ -305,7 +306,7 @@ CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string
     std::string path = str;
     std::replace(path.begin(), path.end(), '\\', '/');
 
-    std::filesystem::path p(path);
+    boost::filesystem::path p(path);
     std::string stem = p.stem().string();
     std::string ext = p.extension().string();
     
@@ -406,7 +407,8 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord)
 
 BsaVersion CompressedBSAFile::detectVersion(const std::string& filePath)
 {
-    std::ifstream input(std::filesystem::path(filePath), std::ios_base::binary);
+    namespace bfs = boost::filesystem;
+    bfs::ifstream input(bfs::path(filePath), std::ios_base::binary);
 
     // Total archive size
     std::streamoff fsize = 0;
diff --git a/components/crashcatcher/crashcatcher.cpp b/components/crashcatcher/crashcatcher.cpp
index d2fad06c72..24dbc00858 100644
--- a/components/crashcatcher/crashcatcher.cpp
+++ b/components/crashcatcher/crashcatcher.cpp
@@ -1,5 +1,4 @@
 #include <stdio.h>
-#include <cstring>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -10,8 +9,6 @@
 #include <string.h>
 #include <errno.h>
 #include <limits.h>
-#include <fstream>
-#include <filesystem>
 
 #include <pthread.h>
 #include <stdbool.h>
@@ -19,6 +16,11 @@
 
 #include <components/debug/debuglog.hpp>
 
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+
+namespace bfs = boost::filesystem;
+
 #include <SDL_messagebox.h>
 
 #ifdef __linux__
@@ -499,10 +501,10 @@ int crashCatcherInstallHandlers(int argc, char **argv, int num_signals, int *sig
 static bool is_debugger_present()
 {
 #if defined (__linux__)
-    std::filesystem::path procstatus = std::filesystem::path("/proc/self/status");
-    if (std::filesystem::exists(procstatus))
+    bfs::path procstatus = bfs::path("/proc/self/status");
+    if (bfs::exists(procstatus))
     {
-        std::ifstream file((procstatus));
+        bfs::ifstream file((procstatus));
         while (!file.eof())
         {
             std::string word;
diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp
index e37406299d..5225c59e85 100644
--- a/components/debug/debugging.cpp
+++ b/components/debug/debugging.cpp
@@ -3,8 +3,6 @@
 #include <chrono>
 #include <memory>
 #include <functional>
-#include <fstream>
-#include <filesystem>
 
 #include <components/crashcatcher/crashcatcher.hpp>
 #include <components/files/configurationmanager.hpp>
@@ -244,7 +242,7 @@ namespace Debug
 static std::unique_ptr<std::ostream> rawStdout = nullptr;
 static std::unique_ptr<std::ostream> rawStderr = nullptr;
 static std::unique_ptr<std::mutex> rawStderrMutex = nullptr;
-static std::ofstream logfile;
+static boost::filesystem::ofstream logfile;
 
 #if defined(_WIN32) && defined(_DEBUG)
 static boost::iostreams::stream_buffer<Debug::DebugOutput> sb;
@@ -278,7 +276,7 @@ void setupLogging(const std::string& logDir, const std::string& appName, std::io
     std::cerr.rdbuf(&sb);
 #else
     const std::string logName = Misc::StringUtils::lowerCase(appName) + ".log";
-    logfile.open(std::filesystem::path(logDir) / logName, mode);
+    logfile.open(boost::filesystem::path(logDir) / logName, mode);
 
     coutsb.open(Debug::Tee(logfile, *rawStdout));
     cerrsb.open(Debug::Tee(logfile, *rawStderr));
diff --git a/components/detournavigator/debug.cpp b/components/detournavigator/debug.cpp
index d274023e78..9c4a51c395 100644
--- a/components/detournavigator/debug.cpp
+++ b/components/detournavigator/debug.cpp
@@ -4,6 +4,9 @@
 #include "settings.hpp"
 #include "settingsutils.hpp"
 
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
 #include <components/bullethelpers/operators.hpp>
 
 #include <DetourNavMesh.h>
@@ -11,8 +14,6 @@
 
 #include <osg/io_utils>
 
-#include <filesystem>
-#include <fstream>
 #include <ostream>
 #include <array>
 #include <string_view>
@@ -195,7 +196,7 @@ namespace DetourNavigator
         const std::string& revision, const RecastSettings& settings)
     {
         const auto path = pathPrefix + "recastmesh" + revision + ".obj";
-        std::ofstream file(std::filesystem::path(path), std::ios::out);
+        boost::filesystem::ofstream file(boost::filesystem::path(path), std::ios::out);
         if (!file.is_open())
             throw NavigatorException("Open file failed: " + path);
         file.exceptions(std::ios::failbit | std::ios::badbit);
@@ -242,7 +243,7 @@ namespace DetourNavigator
         };
 
         const auto path = pathPrefix + "all_tiles_navmesh" + revision + ".bin";
-        std::ofstream file(std::filesystem::path(path), std::ios::out | std::ios::binary);
+        boost::filesystem::ofstream file(boost::filesystem::path(path), std::ios::out | std::ios::binary);
         if (!file.is_open())
             throw NavigatorException("Open file failed: " + path);
         file.exceptions(std::ios::failbit | std::ios::badbit);
diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp
index 3e318cb2a6..5921854190 100644
--- a/components/esm3/esmreader.cpp
+++ b/components/esm3/esmreader.cpp
@@ -2,13 +2,12 @@
 
 #include "readerscache.hpp"
 
+#include <boost/filesystem/path.hpp>
 #include <components/misc/stringops.hpp>
 #include <components/files/openfile.hpp>
 
 #include <stdexcept>
 #include <sstream>
-#include <filesystem>
-#include <fstream>
 
 namespace ESM
 {
@@ -76,9 +75,8 @@ void ESMReader::resolveParentFileIndices(ReadersCache& readers)
             if (reader->getFileSize() == 0)
                 continue;  // Content file in non-ESM format
             const std::string& candidate = reader->getName();
-            std::string fnamecandidate = std::filesystem::path(candidate).filename().string();
-            if (Misc::StringUtils::ciEqual(fname, fnamecandidate))
-            {
+            std::string fnamecandidate = boost::filesystem::path(candidate).filename().string();
+            if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) {
                 index = i;
                 break;
             }
diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp
index 351de8612a..77025d13e3 100644
--- a/components/esm3/esmwriter.cpp
+++ b/components/esm3/esmwriter.cpp
@@ -1,7 +1,7 @@
 #include "esmwriter.hpp"
 
 #include <cassert>
-#include <fstream>
+#include <iostream>
 #include <stdexcept>
 
 #include <components/to_utf8/to_utf8.hpp>
diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp
index 3c0ac470c4..ce27dfbc64 100644
--- a/components/esm4/reader.cpp
+++ b/components/esm4/reader.cpp
@@ -31,7 +31,6 @@
 #include <cassert>
 #include <stdexcept>
 #include <unordered_map>
-#include <filesystem>
 #include <iostream> // for debugging
 #include <sstream>  // for debugging
 #include <iomanip>  // for debugging
@@ -46,6 +45,8 @@
 #endif
 #include <boost/iostreams/filtering_streambuf.hpp>
 #include <boost/iostreams/copy.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
 
 #include <components/bsa/memorystream.hpp>
 #include <components/misc/stringops.hpp>
@@ -204,7 +205,7 @@ void Reader::buildLStringIndex()
     if ((mHeader.mFlags & Rec_ESM) == 0 || (mHeader.mFlags & Rec_Localized) == 0)
         return;
 
-    std::filesystem::path p(mCtx.filename);
+    boost::filesystem::path p(mCtx.filename);
     std::string filename = p.stem().filename().string();
 
     buildLStringIndex("Strings/" + filename + "_English.STRINGS",   Type_Strings);
diff --git a/components/esmloader/load.cpp b/components/esmloader/load.cpp
index d3c170bc4c..a7786e3579 100644
--- a/components/esmloader/load.cpp
+++ b/components/esmloader/load.cpp
@@ -22,7 +22,6 @@
 #include <components/loadinglistener/loadinglistener.hpp>
 
 #include <algorithm>
-#include <filesystem>
 #include <cstddef>
 #include <map>
 #include <set>
@@ -228,7 +227,7 @@ namespace EsmLoader
             for (std::size_t i = 0; i < contentFiles.size(); ++i)
             {
                 const std::string &file = contentFiles[i];
-                const std::string extension = Misc::StringUtils::lowerCase(std::filesystem::path(file).extension().string());
+                const std::string extension = Misc::StringUtils::lowerCase(boost::filesystem::path(file).extension().string());
 
                 if (supportedFormats.find(extension) == supportedFormats.end())
                 {
diff --git a/components/files/openfile.cpp b/components/files/openfile.cpp
index 54b0b28058..7e142bb4e8 100644
--- a/components/files/openfile.cpp
+++ b/components/files/openfile.cpp
@@ -1,25 +1,16 @@
 #include "openfile.hpp"
 
 #include <cstring>
-#include <fstream>
-
-#if defined(_WIN32) || defined(__WINDOWS__)
-#include <boost/locale.hpp>
-#endif
 
 namespace Files
 {
-    std::unique_ptr<std::ifstream> openBinaryInputFileStream(const std::string& path)
+    std::unique_ptr<boost::filesystem::ifstream> openBinaryInputFileStream(const std::string& path)
     {
-#if defined(_WIN32) || defined(__WINDOWS__)
-        std::wstring wpath = boost::locale::conv::utf_to_utf<wchar_t>(path);
-        auto stream = std::make_unique<std::ifstream>(wpath, std::ios::binary);
-#else
-        auto stream = std::make_unique<std::ifstream>(path, std::ios::binary);
-#endif
+        auto stream = std::make_unique<boost::filesystem::ifstream>(path, boost::filesystem::fstream::binary);
+
         if (!stream->is_open())
             throw std::runtime_error("Failed to open '" + path + "' for reading: " + std::strerror(errno));
-        stream->exceptions(std::ios::badbit);
+        stream->exceptions(boost::filesystem::fstream::badbit);
         return stream;
     }
 }
diff --git a/components/files/openfile.hpp b/components/files/openfile.hpp
index 3cecf7bac1..44da718333 100644
--- a/components/files/openfile.hpp
+++ b/components/files/openfile.hpp
@@ -5,9 +5,11 @@
 #include <memory>
 #include <string>
 
+#include <boost/filesystem/fstream.hpp>
+
 namespace Files
 {
-    std::unique_ptr<std::ifstream> openBinaryInputFileStream(const std::string& path);
+    std::unique_ptr<boost::filesystem::ifstream> openBinaryInputFileStream(const std::string& path);
 }
 
 #endif
diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp
index c39518fef0..69ffd296ae 100644
--- a/components/fx/technique.cpp
+++ b/components/fx/technique.cpp
@@ -39,8 +39,8 @@ namespace fx
 {
     Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals)
         : mName(name)
-        , mFileName((std::filesystem::path(Technique::sSubdir) / (mName + Technique::sExt)).string())
-        , mLastModificationTime(std::filesystem::file_time_type())
+        , mFileName((boost::filesystem::path(Technique::sSubdir) / (mName + Technique::sExt)).string())
+        , mLastModificationTime(std::chrono::time_point<std::chrono::system_clock>())
         , mWidth(width)
         , mHeight(height)
         , mVFS(vfs)
@@ -179,10 +179,11 @@ namespace fx
         return mFileName;
     }
 
-    bool Technique::setLastModificationTime(std::filesystem::file_time_type timeStamp)
+    bool Technique::setLastModificationTime(std::time_t timeStamp)
     {
-        const bool isDirty = timeStamp != mLastModificationTime;
-        mLastModificationTime = timeStamp;
+        auto convertedTime = std::chrono::system_clock::from_time_t(timeStamp);
+        const bool isDirty = convertedTime != mLastModificationTime;
+        mLastModificationTime = convertedTime;
         return isDirty;
     }
 
diff --git a/components/fx/technique.hpp b/components/fx/technique.hpp
index 4b1c9f19bb..bd027fa9d6 100644
--- a/components/fx/technique.hpp
+++ b/components/fx/technique.hpp
@@ -1,12 +1,12 @@
 #ifndef OPENMW_COMPONENTS_FX_TECHNIQUE_H
 #define OPENMW_COMPONENTS_FX_TECHNIQUE_H
 
+#include <chrono>
 #include <vector>
 #include <string>
 #include <variant>
 #include <memory>
 #include <unordered_map>
-#include <filesystem>
 
 #include <osg/Node>
 #include <osg/Program>
@@ -20,6 +20,8 @@
 #include <osg/BlendFunc>
 #include <osg/BlendEquation>
 
+#include <boost/filesystem/path.hpp>
+
 #include "pass.hpp"
 #include "lexer.hpp"
 #include "types.hpp"
@@ -131,7 +133,7 @@ namespace fx
 
         std::string getFileName() const;
 
-        bool setLastModificationTime(std::filesystem::file_time_type timeStamp);
+        bool setLastModificationTime(std::time_t timeStamp);
 
         bool isValid() const { return mValid; }
 
@@ -263,7 +265,7 @@ namespace fx
 
         bool mEnabled;
 
-        std::filesystem::file_time_type mLastModificationTime;
+        std::chrono::time_point<std::chrono::system_clock> mLastModificationTime;
         bool mValid;
         bool mHDR;
         bool mNormals;
diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp
index dbdfde5100..4b2e099e05 100644
--- a/components/lua/luastate.cpp
+++ b/components/lua/luastate.cpp
@@ -4,7 +4,7 @@
 #include <luajit.h>
 #endif // NO_LUAJIT
 
-#include <filesystem>
+#include <boost/filesystem.hpp>
 
 #include <components/debug/debuglog.hpp>
 #include <components/vfs/manager.hpp>
@@ -34,12 +34,12 @@ namespace LuaUtil
         path.append(".lua");
         for (const std::string& dir : searchDirs)
         {
-            std::filesystem::path base(dir);
-            std::filesystem::path p1 = base / path;
-            if (std::filesystem::exists(p1))
+            boost::filesystem::path base(dir);
+            boost::filesystem::path p1 = base / path;
+            if (boost::filesystem::exists(p1))
                 return p1.string();
-            std::filesystem::path p2 = base / pathWithInit;
-            if (std::filesystem::exists(p2))
+            boost::filesystem::path p2 = base / pathWithInit;
+            if (boost::filesystem::exists(p2))
                 return p2.string();
         }
         throw std::runtime_error("module not found: " + std::string(packageName));
diff --git a/components/lua/storage.cpp b/components/lua/storage.cpp
index bff978b633..51c06e9325 100644
--- a/components/lua/storage.cpp
+++ b/components/lua/storage.cpp
@@ -1,7 +1,7 @@
 #include "storage.hpp"
 
-#include <filesystem>
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
 
 #include <components/debug/debuglog.hpp>
 
@@ -155,13 +155,13 @@ namespace LuaUtil
         }
     }
 
-    void LuaStorage::load(const std::string& path)
+    void LuaStorage::load(const boost::filesystem::path& path)
     {
         assert(mData.empty());  // Shouldn't be used before loading
         try
         {
-            Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)";
-            std::ifstream fin(path, std::fstream::binary);
+            Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << boost::filesystem::file_size(path) << " bytes)";
+            boost::filesystem::ifstream fin(path, boost::filesystem::fstream::binary);
             std::string serializedData((std::istreambuf_iterator<char>(fin)), std::istreambuf_iterator<char>());
             sol::table data = deserialize(mLua, serializedData);
             for (const auto& [sectionName, sectionTable] : data)
@@ -177,7 +177,7 @@ namespace LuaUtil
         }
     }
 
-    void LuaStorage::save(const std::string& path) const
+    void LuaStorage::save(const boost::filesystem::path& path) const
     {
         sol::table data(mLua, sol::create);
         for (const auto& [sectionName, section] : mData)
@@ -187,7 +187,7 @@ namespace LuaUtil
         }
         std::string serializedData = serialize(data);
         Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)";
-        std::ofstream fout(path, std::fstream::binary);
+        boost::filesystem::ofstream fout(path, boost::filesystem::ofstream::binary);
         fout.write(serializedData.data(), serializedData.size());
         fout.close();
     }
diff --git a/components/lua/storage.hpp b/components/lua/storage.hpp
index 8ae944c5ab..b2fbde4abe 100644
--- a/components/lua/storage.hpp
+++ b/components/lua/storage.hpp
@@ -4,6 +4,8 @@
 #include <map>
 #include <sol/sol.hpp>
 
+#include <boost/filesystem/path.hpp>
+
 #include "scriptscontainer.hpp"
 #include "serialization.hpp"
 
@@ -18,8 +20,8 @@ namespace LuaUtil
         explicit LuaStorage(lua_State* lua) : mLua(lua) {}
 
         void clearTemporaryAndRemoveCallbacks();
-        void load(const std::string& path);
-        void save(const std::string& path) const;
+        void load(const boost::filesystem::path& path);
+        void save(const boost::filesystem::path& path) const;
 
         sol::object getSection(std::string_view sectionName, bool readOnly);
         sol::object getMutableSection(std::string_view sectionName) { return getSection(sectionName, false); }
diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp
index 094220938b..f1e68ee11b 100644
--- a/components/resource/scenemanager.cpp
+++ b/components/resource/scenemanager.cpp
@@ -1,7 +1,6 @@
 #include "scenemanager.hpp"
 
 #include <cstdlib>
-#include <filesystem>
 
 #include <osg/AlphaFunc>
 #include <osg/Group>
@@ -18,6 +17,8 @@
 #include <osgDB/SharedStateManager>
 #include <osgDB/Registry>
 
+#include <boost/filesystem.hpp>
+
 #include <components/debug/debuglog.hpp>
 
 #include <components/nifosg/nifloader.hpp>
@@ -496,11 +497,11 @@ namespace Resource
 
         osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) override
         {
-            std::filesystem::path filePath(filename);
+            boost::filesystem::path filePath(filename);
             if (filePath.is_absolute())
                 // It is a hack. Needed because either OSG or libcollada-dom tries to make an absolute path from
                 // our relative VFS path by adding current working directory.
-                filePath = std::filesystem::relative(filename, osgDB::getCurrentWorkingDirectory());
+                filePath = boost::filesystem::relative(filename, osgDB::getCurrentWorkingDirectory());
             try
             {
                 return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(filePath.string()),
diff --git a/components/sceneutil/screencapture.cpp b/components/sceneutil/screencapture.cpp
index 97a22e94aa..99cb535326 100644
--- a/components/sceneutil/screencapture.cpp
+++ b/components/sceneutil/screencapture.cpp
@@ -8,10 +8,10 @@
 #include <osgDB/ReaderWriter>
 #include <osgDB/Registry>
 
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
 
 #include <cassert>
-#include <fstream>
-#include <filesystem>
 #include <iomanip>
 #include <sstream>
 #include <string>
@@ -82,10 +82,10 @@ namespace SceneUtil
             lastFileName = stream.str();
             lastFilePath = screenshotPath + "/" + lastFileName;
 
-        } while (std::filesystem::exists(lastFilePath));
+        } while (boost::filesystem::exists(lastFilePath));
 
-        std::ofstream outStream;
-        outStream.open(std::filesystem::path(std::move(lastFilePath)), std::ios::binary);
+        boost::filesystem::ofstream outStream;
+        outStream.open(boost::filesystem::path(std::move(lastFilePath)), std::ios::binary);
 
         osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(screenshotFormat);
         if (!readerwriter)
diff --git a/components/sceneutil/writescene.cpp b/components/sceneutil/writescene.cpp
index d243f521c0..6be963ef2e 100644
--- a/components/sceneutil/writescene.cpp
+++ b/components/sceneutil/writescene.cpp
@@ -1,10 +1,10 @@
 #include "writescene.hpp"
 
 #include <stdexcept>
-#include <fstream>
 
 #include <osgDB/Registry>
 
+#include <boost/filesystem/fstream.hpp>
 
 #include "serialize.hpp"
 
@@ -16,7 +16,7 @@ void SceneUtil::writeScene(osg::Node *node, const std::string& filename, const s
     if (!rw)
         throw std::runtime_error("can not find readerwriter for " + format);
 
-    std::ofstream stream;
+    boost::filesystem::ofstream stream;
     stream.open(filename);
 
     osg::ref_ptr<osgDB::Options> options = new osgDB::Options;
diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp
index 778888d2d2..dd1b8c1a20 100644
--- a/components/settings/parser.cpp
+++ b/components/settings/parser.cpp
@@ -5,8 +5,7 @@
 #include <components/debug/debuglog.hpp>
 #include <components/misc/stringops.hpp>
 
-#include <fstream>
-#include <filesystem>
+#include <boost/filesystem/fstream.hpp>
 
 #include <Base64.h>
 
@@ -14,8 +13,8 @@ void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, Cat
                                                     bool base64Encoded, bool overrideExisting)
 {
     mFile = file;
-    std::ifstream fstream;
-    fstream.open(std::filesystem::path(file));
+    boost::filesystem::ifstream fstream;
+    fstream.open(boost::filesystem::path(file));
     auto stream = std::ref<std::istream>(fstream);
 
     std::istringstream decodedStream;
@@ -107,8 +106,8 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::string& file, con
     // Open the existing settings.cfg file to copy comments.  This might not be the same file
     // as the output file if we're copying the setting from the default settings.cfg for the
     // first time.  A minor change in API to pass the source file might be in order here.
-    std::ifstream istream;
-    std::filesystem::path ipath(file);
+    boost::filesystem::ifstream istream;
+    boost::filesystem::path ipath(file);
     istream.open(ipath);
 
     // Create a new string stream to write the current settings to.  It's likely that the
@@ -306,7 +305,7 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::string& file, con
     // Now install the newly written file in the requested place.
     if (changed) {
         Log(Debug::Info) << "Updating settings file: " << ipath;
-        std::ofstream ofstream;
+        boost::filesystem::ofstream ofstream;
         ofstream.open(ipath);
         ofstream << ostream.rdbuf();
         ofstream.close();
diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp
index dfd124f3cf..85304a24cf 100644
--- a/components/settings/settings.cpp
+++ b/components/settings/settings.cpp
@@ -1,7 +1,6 @@
 #include "settings.hpp"
 #include "parser.hpp"
 
-#include <filesystem>
 #include <sstream>
 
 #include <components/files/configurationmanager.hpp>
@@ -45,7 +44,7 @@ std::string Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEd
 
     // Create the settings manager and load default settings file.
     const std::string defaultsBin = (paths.front() / defaultSettingsFile).string();
-    if (!std::filesystem::exists(defaultsBin))
+    if (!boost::filesystem::exists(defaultsBin))
         throw std::runtime_error ("No default settings file found! Make sure the file \"" + defaultSettingsFile + "\" was properly installed.");
     parser.loadSettingsFile(defaultsBin, mDefaultSettings, true, false);
 
@@ -53,13 +52,13 @@ std::string Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEd
     for (int i = 0; i < static_cast<int>(paths.size()) - 1; ++i)
     {
         const std::string additionalDefaults = (paths[i] / userSettingsFile).string();
-        if (std::filesystem::exists(additionalDefaults))
+        if (boost::filesystem::exists(additionalDefaults))
             parser.loadSettingsFile(additionalDefaults, mDefaultSettings, false, true);
     }
 
     // Load "settings.cfg" or "openmw-cs.cfg" from the last config dir as user settings. This path will be used to save modified settings.
     std::string settingspath = (paths.back() / userSettingsFile).string();
-    if (std::filesystem::exists(settingspath))
+    if (boost::filesystem::exists(settingspath))
         parser.loadSettingsFile(settingspath, mUserSettings, false, false);
 
     return settingspath;
diff --git a/components/settings/shadermanager.hpp b/components/settings/shadermanager.hpp
index eaf10a3a34..05e9e2c1b7 100644
--- a/components/settings/shadermanager.hpp
+++ b/components/settings/shadermanager.hpp
@@ -2,9 +2,7 @@
 #define OPENMW_COMPONENTS_SETTINGS_SHADERMANAGER_H
 
 #include <unordered_map>
-#include <filesystem>
 #include <optional>
-#include <fstream>
 #include <vector>
 
 #include <yaml-cpp/yaml.h>
@@ -13,6 +11,10 @@
 #include <osg/Vec3f>
 #include <osg/Vec4f>
 
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
 #include <components/serialization/osgyaml.hpp>
 #include <components/debug/debuglog.hpp>
 
@@ -107,13 +109,13 @@ namespace Settings
         bool load(const std::string& path)
         {
             mData = YAML::Null;
-            mPath = std::filesystem::path(path);
+            mPath = boost::filesystem::path(path);
 
             Log(Debug::Info) << "Loading shader settings file: " << mPath;
 
-            if (!std::filesystem::exists(mPath))
+            if (!boost::filesystem::exists(mPath))
             {
-                std::ofstream fout(mPath);
+                boost::filesystem::ofstream fout(mPath);
                 if (!fout)
                 {
                     Log(Debug::Error) << "Failed creating shader settings file: " << mPath;
@@ -123,7 +125,8 @@ namespace Settings
 
             try
             {
-                mData = YAML::LoadFile(mPath.string());
+                boost::filesystem::ifstream fin(mPath);
+                mData = YAML::Load(fin);
                 mData.SetStyle(YAML::EmitterStyle::Block);
 
                 if (!mData["config"])
@@ -153,7 +156,7 @@ namespace Settings
             out.SetMapFormat(YAML::Block);
             out << mData;
 
-            std::ofstream fout(mPath.string());
+            boost::filesystem::ofstream fout(mPath);
             fout << out.c_str();
 
             if (!fout)
@@ -166,7 +169,7 @@ namespace Settings
         }
 
     private:
-        std::filesystem::path mPath;
+        boost::filesystem::path mPath;
         YAML::Node mData;
         Mode mMode = Mode::Normal;
     };
diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp
index 4b64b07dd6..cb7369b4df 100644
--- a/components/shader/shadermanager.cpp
+++ b/components/shader/shadermanager.cpp
@@ -1,15 +1,19 @@
 #include "shadermanager.hpp"
 
-#include <fstream>
 #include <algorithm>
 #include <sstream>
 #include <regex>
-#include <filesystem>
 #include <set>
 #include <unordered_map>
 #include <chrono>
+
 #include <osg/Program>
 #include <osgViewer/Viewer>
+
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
 #include <components/debug/debuglog.hpp>
 #include <components/misc/stringops.hpp>
 #include <components/settings/settings.hpp>
@@ -73,7 +77,7 @@ namespace Shader
     // Recursively replaces include statements with the actual source of the included files.
     // Adjusts #line statements accordingly and detects cyclic includes.
     // cycleIncludeChecker is the set of files that include this file directly or indirectly, and is intentionally not a reference to allow automatic cleanup.
-    static bool parseIncludes(const std::filesystem::path& shaderPath, std::string& source, const std::string& fileName, int& fileNumber, std::set<std::filesystem::path> cycleIncludeChecker,std::set<std::filesystem::path>& includedFiles)
+    static bool parseIncludes(const boost::filesystem::path& shaderPath, std::string& source, const std::string& fileName, int& fileNumber, std::set<boost::filesystem::path> cycleIncludeChecker,std::set<boost::filesystem::path>& includedFiles)
     {
         includedFiles.insert(shaderPath / fileName);
         // An include is cyclic if it is being included by itself
@@ -101,7 +105,7 @@ namespace Shader
                 return false;
             }
             std::string includeFilename = source.substr(start + 1, end - (start + 1));
-            std::filesystem::path includePath = shaderPath / includeFilename;
+            boost::filesystem::path includePath = shaderPath / includeFilename;
 
             // Determine the line number that will be used for the #line directive following the included source
             size_t lineDirectivePosition = source.rfind("#line", foundPos);
@@ -121,7 +125,7 @@ namespace Shader
             lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n');
 
             // Include the file recursively
-            std::ifstream includeFstream;
+            boost::filesystem::ifstream includeFstream;
             includeFstream.open(includePath);
             if (includeFstream.fail())
             {
@@ -366,8 +370,8 @@ namespace Shader
         using KeysHolder = std::set<ShaderManager::MapKey>;
 
         std::unordered_map<std::string, KeysHolder> mShaderFiles;
-        std::unordered_map<std::string, std::set<std::filesystem::path>> templateIncludedFiles;
-        std::filesystem::file_time_type mLastAutoRecompileTime;
+        std::unordered_map<std::string, std::set<boost::filesystem::path>> templateIncludedFiles;
+        std::chrono::time_point<std::chrono::system_clock> mLastAutoRecompileTime;
         bool mHotReloadEnabled;
         bool mTriggerReload;
 
@@ -375,13 +379,13 @@ namespace Shader
         {
             mTriggerReload = false;
             mHotReloadEnabled = false;
-            mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now();
+            mLastAutoRecompileTime = std::chrono::system_clock::now();
         }
 
         void addShaderFiles(const std::string& templateName,const ShaderManager::DefineMap& defines )
         {
-            const std::set<std::filesystem::path>& shaderFiles = templateIncludedFiles[templateName];
-            for (const std::filesystem::path& file : shaderFiles)
+            const std::set<boost::filesystem::path>& shaderFiles = templateIncludedFiles[templateName];
+            for (const boost::filesystem::path& file : shaderFiles)
             {
                 mShaderFiles[file.string()].insert(std::make_pair(templateName, defines));
             }
@@ -389,7 +393,7 @@ namespace Shader
 
         void update(ShaderManager& Manager,osgViewer::Viewer& viewer)
         {
-            auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(std::filesystem::file_time_type::clock::now() - mLastAutoRecompileTime);
+            auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - mLastAutoRecompileTime);
             if ((mHotReloadEnabled && timeSinceLastCheckMillis.count() > 200) || mTriggerReload == true)
             {
                 reloadTouchedShaders(Manager, viewer);
@@ -403,7 +407,7 @@ namespace Shader
             for (auto& [pathShaderToTest,  shaderKeys]: mShaderFiles)
             {
 
-                std::filesystem::file_time_type write_time = std::filesystem::last_write_time(pathShaderToTest);
+                auto write_time = std::chrono::system_clock::from_time_t(boost::filesystem::last_write_time(pathShaderToTest));
                 if (write_time.time_since_epoch() > mLastAutoRecompileTime.time_since_epoch())
                 {
                     if (!threadsRunningToStop)
@@ -419,9 +423,9 @@ namespace Shader
 
                         ShaderManager::TemplateMap::iterator templateIt = Manager.mShaderTemplates.find(templateName); //Can't be Null, if we're here it means the template was added
                         std::string& shaderSource = templateIt->second;
-                        std::set<std::filesystem::path> insertedPaths;
-                        std::filesystem::path path = (std::filesystem::path(Manager.mPath) / templateName);
-                        std::ifstream stream;
+                        std::set<boost::filesystem::path> insertedPaths;
+                        boost::filesystem::path path = (boost::filesystem::path(Manager.mPath) / templateName);
+                        boost::filesystem::ifstream stream;
                         stream.open(path);
                         if (stream.fail())
                         {
@@ -434,7 +438,7 @@ namespace Shader
                         int fileNumber = 1;
                         std::string source = buffer.str();
                         if (!addLineDirectivesAfterConditionalBlocks(source)
-                            || !parseIncludes(std::filesystem::path(Manager.mPath), source, templateName, fileNumber, {}, insertedPaths))
+                            || !parseIncludes(boost::filesystem::path(Manager.mPath), source, templateName, fileNumber, {}, insertedPaths))
                         {
                             break;
                         }
@@ -452,7 +456,7 @@ namespace Shader
             }
             if (threadsRunningToStop)
                 viewer.startThreading();
-            mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now();
+            mLastAutoRecompileTime = std::chrono::system_clock::now();
         }
     };
 
@@ -462,12 +466,12 @@ namespace Shader
 
         // read the template if we haven't already
         TemplateMap::iterator templateIt = mShaderTemplates.find(templateName);
-        std::set<std::filesystem::path> insertedPaths;
+        std::set<boost::filesystem::path> insertedPaths;
 
         if (templateIt == mShaderTemplates.end())
         {
-            std::filesystem::path path = (std::filesystem::path(mPath) / templateName);
-            std::ifstream stream;
+            boost::filesystem::path path = (boost::filesystem::path(mPath) / templateName);
+            boost::filesystem::ifstream stream;
             stream.open(path);
             if (stream.fail())
             {
@@ -481,7 +485,7 @@ namespace Shader
             int fileNumber = 1;
             std::string source = buffer.str();
             if (!addLineDirectivesAfterConditionalBlocks(source)
-                || !parseIncludes(std::filesystem::path(mPath), source, templateName, fileNumber, {}, insertedPaths))
+                || !parseIncludes(boost::filesystem::path(mPath), source, templateName, fileNumber, {}, insertedPaths))
                 return nullptr;
             mHotReloadManager->templateIncludedFiles[templateName] = insertedPaths;
             templateIt = mShaderTemplates.insert(std::make_pair(templateName, source)).first;
diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp
index bc6ba1c44d..f2cdd803e7 100644
--- a/components/translation/translation.cpp
+++ b/components/translation/translation.cpp
@@ -1,6 +1,6 @@
 #include "translation.hpp"
 
-#include <fstream>
+#include <boost/filesystem/fstream.hpp>
 
 namespace Translation
 {
@@ -32,8 +32,8 @@ namespace Translation
 
         if (dataFileCollections.getCollection (extension).doesExist (fileName))
         {
-            std::ifstream stream (
-                dataFileCollections.getCollection (extension).getPath (fileName).c_str());
+            boost::filesystem::ifstream stream (
+                dataFileCollections.getCollection (extension).getPath (fileName));
 
             if (!stream.is_open())
                 throw std::runtime_error ("failed to open translation file: " + fileName);
diff --git a/components/version/version.cpp b/components/version/version.cpp
index 32b8f44ae6..fecbdcb3f9 100644
--- a/components/version/version.cpp
+++ b/components/version/version.cpp
@@ -1,16 +1,16 @@
 #include "version.hpp"
 
-#include <filesystem>
-#include <fstream>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 namespace Version
 {
 
 Version getOpenmwVersion(const std::string &resourcePath)
 {
-    std::filesystem::path path (resourcePath + "/version");
+    boost::filesystem::path path (resourcePath + "/version");
 
-    std::ifstream stream (path);
+    boost::filesystem::ifstream stream (path);
 
     Version v;
     std::getline(stream, v.mVersion);
diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp
index 7b57c93944..3619a12601 100644
--- a/components/vfs/filesystemarchive.cpp
+++ b/components/vfs/filesystemarchive.cpp
@@ -2,7 +2,7 @@
 
 #include <algorithm>
 
-#include <filesystem>
+#include <boost/filesystem.hpp>
 
 #include <components/debug/debuglog.hpp>
 #include <components/files/constrainedfilestream.hpp>
@@ -21,7 +21,7 @@ namespace VFS
     {
         if (!mBuiltIndex)
         {
-            typedef std::filesystem::recursive_directory_iterator directory_iterator;
+            typedef boost::filesystem::recursive_directory_iterator directory_iterator;
 
             directory_iterator end;
 
@@ -30,14 +30,14 @@ namespace VFS
             if (mPath.size () > 0 && mPath [prefix - 1] != '\\' && mPath [prefix - 1] != '/')
                 ++prefix;
 
-            for (directory_iterator i (std::filesystem::u8path(mPath)); i != end; ++i)
+            for (directory_iterator i (mPath); i != end; ++i)
             {
-                if(std::filesystem::is_directory (*i))
+                if(boost::filesystem::is_directory (*i))
                     continue;
 
-                auto proper = i->path ().u8string ();
+                std::string proper = i->path ().string ();
 
-                FileSystemArchiveFile file(std::string((char*)proper.c_str(), proper.size()));
+                FileSystemArchiveFile file(proper);
 
                 std::string searchable;
 
@@ -45,7 +45,7 @@ namespace VFS
 
                 const auto inserted = mIndex.insert(std::make_pair(searchable, file));
                 if (!inserted.second)
-                    Log(Debug::Warning) << "Warning: found duplicate file for '" << std::string((char*)proper.c_str(), proper.size()) << "', please check your file system for two files with the same name in different cases.";
+                    Log(Debug::Warning) << "Warning: found duplicate file for '" << proper << "', please check your file system for two files with the same name in different cases.";
                 else
                     out[inserted.first->first] = &inserted.first->second;
             }
diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp
index 25ee9e1f62..25519d46c5 100644
--- a/components/vfs/registerarchives.cpp
+++ b/components/vfs/registerarchives.cpp
@@ -1,7 +1,6 @@
 #include "registerarchives.hpp"
 
 #include <set>
-#include <filesystem>
 #include <stdexcept>
 
 #include <components/debug/debuglog.hpp>
@@ -39,11 +38,10 @@ namespace VFS
 
         if (useLooseFiles)
         {
-            std::set<std::filesystem::path> seen;
+            std::set<boost::filesystem::path> seen;
             for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
             {
-                // TODO(jvoisin) Get rid of `->native()` when we move PathContainer from boost::filesystem to std::filesystem.
-                if (seen.insert(iter->native()).second)
+                if (seen.insert(*iter).second)
                 {
                     Log(Debug::Info) << "Adding data directory " << iter->string();
                     // Last data dir has the highest priority
diff --git a/extern/oics/ICSPrerequisites.h b/extern/oics/ICSPrerequisites.h
index ed99f4f54f..fa0b72f5cb 100644
--- a/extern/oics/ICSPrerequisites.h
+++ b/extern/oics/ICSPrerequisites.h
@@ -31,7 +31,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 /// Include external headers
 #include <sstream>
-#include <fstream>
 #include <vector>
 #include <map>
 #include <list>