diff --git a/dune/vtk/pvdwriter.hh b/dune/vtk/pvdwriter.hh
index 76fe74bd0b84fa70821ee9385acfc3862c35c2d1..a752176e7dcab82580d7a7003ad8a5c0021f83c7 100644
--- a/dune/vtk/pvdwriter.hh
+++ b/dune/vtk/pvdwriter.hh
@@ -49,7 +49,7 @@ namespace Dune
 
   protected:
     /// Write a series of vtk files in a .pvd ParaView Data file
-    void writeFile (double time, std::string const& filename) const;
+    void writeFile (double time, std::ofstream& out) const;
 
   protected:
     VtkWriter vtkWriter_;
diff --git a/dune/vtk/pvdwriter.impl.hh b/dune/vtk/pvdwriter.impl.hh
index 83a7666e5c62cd49802ccfa03b42709b18ce54c6..fd43b803343be5ed3e213d1e3e63d31ef9b22e0e 100644
--- a/dune/vtk/pvdwriter.impl.hh
+++ b/dune/vtk/pvdwriter.impl.hh
@@ -31,23 +31,24 @@ void PvdWriter<W>
   timesteps_.emplace_back(time, filename + ext);
   vtkWriter_.write(filename + ext);
 
-  if (rank == 0)
-    writeFile(time, p.string() + ".pvd");
+  if (rank == 0) {
+    std::ofstream out(p.string() + ".pvd", std::ios_base::ate | std::ios::binary);
+    assert(out.is_open());
+
+    out.imbue(std::locale::classic());
+    out << std::setprecision(datatype_ == Vtk::FLOAT32
+      ? std::numeric_limits<float>::digits10+2
+      : std::numeric_limits<double>::digits10+2);
+
+    writeFile(time, out);
+  }
 }
 
 
 template <class W>
 void PvdWriter<W>
-  ::writeFile (double time, std::string const& filename) const
+  ::writeFile (double time, std::ofstream& out) const
 {
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
-  if (datatype_ == Vtk::FLOAT32)
-    out << std::setprecision(std::numeric_limits<float>::digits10+2);
-  else
-    out << std::setprecision(std::numeric_limits<double>::digits10+2);
-
   out << "<?xml version=\"1.0\"?>\n";
   out << "<VTKFile"
       << " type=\"Collection\""
diff --git a/dune/vtk/vtktimeserieswriter.impl.hh b/dune/vtk/vtktimeserieswriter.impl.hh
index beac3b66521a21d59e95288aba0aceb9b30bc993..3b886ec0de9ec079ff2a3d832376db8ba9aae41a 100644
--- a/dune/vtk/vtktimeserieswriter.impl.hh
+++ b/dune/vtk/vtktimeserieswriter.impl.hh
@@ -70,7 +70,7 @@ void VtkTimeseriesWriter<W>
   p.remove_filename();
   p /= name.string();
 
-  std::string filenameBase = p.string() + "_ts";
+  std::string filename = p.string() + "_ts";
 
   int rank = 0;
   int num_ranks = 1;
@@ -78,15 +78,36 @@ void VtkTimeseriesWriter<W>
     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
     if (num_ranks > 1)
-      filenameBase = p.string() + "_ts_p" + std::to_string(rank);
+      filename = p.string() + "_ts_p" + std::to_string(rank);
 #endif
 
-  std::string filename = filenameBase + "." + vtkWriter_.getFileExtension();
-  vtkWriter_.writeTimeseriesSerialFile(filename, filenameMesh_, timesteps_, blocks_);
+  { // write serial file
+    std::ofstream serial_out(filename + "." + vtkWriter_.getFileExtension(),
+                             std::ios_base::ate | std::ios::binary);
+    assert(serial_out.is_open());
+
+    serial_out.imbue(std::locale::classic());
+    serial_out << std::setprecision(vtkWriter_.getDatatype() == Vtk::FLOAT32
+      ? std::numeric_limits<float>::digits10+2
+      : std::numeric_limits<double>::digits10+2);
+
+    vtkWriter_.writeTimeseriesSerialFile(serial_out, filenameMesh_, timesteps_, blocks_);
+  }
 
 #ifdef HAVE_MPI
-  if (num_ranks > 1 && rank == 0)
-    vtkWriter_.writeTimeseriesParallelFile(p.string() + "_ts", num_ranks, timesteps_);
+  if (num_ranks > 1 && rank == 0) {
+    // write parallel file
+    std::ofstream parallel_out(p.string() + "_ts.p" + vtkWriter_.getFileExtension(),
+                               std::ios_base::ate | std::ios::binary);
+    assert(parallel_out.is_open());
+
+    parallel_out.imbue(std::locale::classic());
+    parallel_out << std::setprecision(vtkWriter_.getDatatype() == Vtk::FLOAT32
+      ? std::numeric_limits<float>::digits10+2
+      : std::numeric_limits<double>::digits10+2);
+
+    vtkWriter_.writeTimeseriesParallelFile(parallel_out, p.string() + "_ts", num_ranks, timesteps_);
+  }
 #endif
 
   // remove all temporary data files
diff --git a/dune/vtk/vtkwriterinterface.hh b/dune/vtk/vtkwriterinterface.hh
index 4fa6b7ff7f431c7477a8e53311b20f7432ad5988..ffc1a5ba0e1e96d5ffb120e8b84704bee597ffba 100644
--- a/dune/vtk/vtkwriterinterface.hh
+++ b/dune/vtk/vtkwriterinterface.hh
@@ -80,12 +80,12 @@ namespace Dune
 
   private:
     /// Write a serial VTK file in Unstructured format
-    virtual void writeSerialFile (std::string const& filename) const = 0;
+    virtual void writeSerialFile (std::ofstream& out) const = 0;
 
     /// Write a parallel VTK file `pfilename.pvtu` in Unstructured format,
     /// with `size` the number of pieces and serial files given by `pfilename_p[i].vtu`
     /// for [i] in [0,...,size).
-    virtual void writeParallelFile (std::string const& pfilename, int size) const = 0;
+    virtual void writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const = 0;
 
     /// Return the file extension of the serial file (not including the dot)
     virtual std::string fileExtension () const = 0;
diff --git a/dune/vtk/vtkwriterinterface.impl.hh b/dune/vtk/vtkwriterinterface.impl.hh
index 28692e8999211f36f6d902c1b86fee2b30511cc7..4242cf624de5e3b1ad79148be7865f8b4f59b12a 100644
--- a/dune/vtk/vtkwriterinterface.impl.hh
+++ b/dune/vtk/vtkwriterinterface.impl.hh
@@ -28,7 +28,7 @@ void VtkWriterInterface<GV,DC>
   p.remove_filename();
   p /= name.string();
 
-  std::string filename = p.string() + "." + fileExtension();
+  std::string filename = p.string();
 
   int rank = 0;
   int num_ranks = 1;
@@ -37,14 +37,34 @@ void VtkWriterInterface<GV,DC>
   MPI_Comm_rank(MPI_COMM_WORLD, &rank);
   MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
   if (num_ranks > 1)
-    filename = p.string() + "_p" + std::to_string(rank) + "." + fileExtension();
+    filename = p.string() + "_p" + std::to_string(rank);
 #endif
 
-  writeSerialFile(filename);
+  { // write serial file
+    std::ofstream serial_out(filename + "." + fileExtension(), std::ios_base::ate | std::ios::binary);
+    assert(serial_out.is_open());
+
+    serial_out.imbue(std::locale::classic());
+    serial_out << std::setprecision(datatype_ == Vtk::FLOAT32
+      ? std::numeric_limits<float>::digits10+2
+      : std::numeric_limits<double>::digits10+2);
+
+    writeSerialFile(serial_out);
+  }
 
 #ifdef HAVE_MPI
-  if (num_ranks > 1 && rank == 0)
-    writeParallelFile(p.string(), num_ranks);
+  if (num_ranks > 1 && rank == 0) {
+    // write parallel file
+    std::ofstream parallel_out(p.string() + ".p" + fileExtension(), std::ios_base::ate | std::ios::binary);
+    assert(parallel_out.is_open());
+
+    parallel_out.imbue(std::locale::classic());
+    parallel_out << std::setprecision(datatype_ == Vtk::FLOAT32
+      ? std::numeric_limits<float>::digits10+2
+      : std::numeric_limits<double>::digits10+2);
+
+    writeParallelFile(parallel_out, p.string(), num_ranks);
+  }
 #endif
 }
 
diff --git a/dune/vtk/writers/vtkimagedatawriter.hh b/dune/vtk/writers/vtkimagedatawriter.hh
index cc6f04e772562b96bc617e8d16a9b3da6c61ede4..50db5b7e7d38877f1afbda07637cb36bb76a2b02 100644
--- a/dune/vtk/writers/vtkimagedatawriter.hh
+++ b/dune/vtk/writers/vtkimagedatawriter.hh
@@ -37,12 +37,12 @@ namespace Dune
 
   private:
     /// Write a serial VTK file in Unstructured format
-    virtual void writeSerialFile (std::string const& filename) const override;
+    virtual void writeSerialFile (std::ofstream& out) const override;
 
     /// Write a parallel VTK file `pfilename.pvtu` in Unstructured format,
     /// with `size` the number of pieces and serial files given by `pfilename_p[i].vtu`
     /// for [i] in [0,...,size).
-    virtual void writeParallelFile (std::string const& pfilename, int size) const override;
+    virtual void writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const override;
 
     virtual std::string fileExtension () const override
     {
diff --git a/dune/vtk/writers/vtkimagedatawriter.impl.hh b/dune/vtk/writers/vtkimagedatawriter.impl.hh
index b976b428d85686ca7ff1c69f40b429290d594ac8..f37691c15ee8bab071eb5719838d027c6355b651 100644
--- a/dune/vtk/writers/vtkimagedatawriter.impl.hh
+++ b/dune/vtk/writers/vtkimagedatawriter.impl.hh
@@ -18,18 +18,8 @@ namespace Dune {
 
 template <class GV, class DC>
 void VtkImageDataWriter<GV,DC>
-  ::writeSerialFile (std::string const& filename) const
+  ::writeSerialFile (std::ofstream& out) const
 {
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
-  if (format_ == Vtk::ASCII) {
-    if (datatype_ == Vtk::FLOAT32)
-      out << std::setprecision(std::numeric_limits<float>::digits10+2);
-    else
-      out << std::setprecision(std::numeric_limits<double>::digits10+2);
-  }
-
   std::vector<pos_type> offsets; // pos => offset
   out << "<VTKFile"
       << " type=\"ImageData\""
@@ -74,12 +64,8 @@ void VtkImageDataWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkImageDataWriter<GV,DC>
-  ::writeParallelFile (std::string const& pfilename, int /*size*/) const
+  ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int /*size*/) const
 {
-  std::string filename = pfilename + ".p" + this->fileExtension();
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
   out << "<VTKFile"
       << " type=\"PImageData\""
       << " version=\"1.0\""
diff --git a/dune/vtk/writers/vtkrectilineargridwriter.hh b/dune/vtk/writers/vtkrectilineargridwriter.hh
index 050e899bd9fc9dc3c2c9d518bce388c13b7586be..f7c0317c197abb745f56379bc8c1f7367c5b7252 100644
--- a/dune/vtk/writers/vtkrectilineargridwriter.hh
+++ b/dune/vtk/writers/vtkrectilineargridwriter.hh
@@ -37,12 +37,12 @@ namespace Dune
 
   private:
     /// Write a serial VTK file in Unstructured format
-    virtual void writeSerialFile (std::string const& filename) const override;
+    virtual void writeSerialFile (std::ofstream& out) const override;
 
     /// Write a parallel VTK file `pfilename.pvtu` in Unstructured format,
     /// with `size` the number of pieces and serial files given by `pfilename_p[i].vtu`
     /// for [i] in [0,...,size).
-    virtual void writeParallelFile (std::string const& pfilename, int size) const override;
+    virtual void writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const override;
 
     void writeCoordinates (std::ofstream& out, std::vector<pos_type>& offsets,
                            Std::optional<std::size_t> timestep = {}) const;
diff --git a/dune/vtk/writers/vtkrectilineargridwriter.impl.hh b/dune/vtk/writers/vtkrectilineargridwriter.impl.hh
index 48a650ee3646ff6e7de7a23840fd560e4dfd180c..3ac723566d7334d8e79ca8ae11de5061a934c1a3 100644
--- a/dune/vtk/writers/vtkrectilineargridwriter.impl.hh
+++ b/dune/vtk/writers/vtkrectilineargridwriter.impl.hh
@@ -18,17 +18,8 @@ namespace Dune {
 
 template <class GV, class DC>
 void VtkRectilinearGridWriter<GV,DC>
-  ::writeSerialFile (std::string const& filename) const
+  ::writeSerialFile (std::ofstream& out) const
 {
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-  if (format_ == Vtk::ASCII) {
-    if (datatype_ == Vtk::FLOAT32)
-      out << std::setprecision(std::numeric_limits<float>::digits10+2);
-    else
-      out << std::setprecision(std::numeric_limits<double>::digits10+2);
-  }
-
   std::vector<pos_type> offsets; // pos => offset
   out << "<VTKFile"
       << " type=\"RectilinearGrid\""
@@ -74,12 +65,8 @@ void VtkRectilinearGridWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkRectilinearGridWriter<GV,DC>
-  ::writeParallelFile (std::string const& pfilename, int /*size*/) const
+  ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int /*size*/) const
 {
-  std::string filename = pfilename + ".p" + this->fileExtension();
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
   out << "<VTKFile"
       << " type=\"PRectilinearGrid\""
       << " version=\"1.0\""
diff --git a/dune/vtk/writers/vtkstructuredgridwriter.hh b/dune/vtk/writers/vtkstructuredgridwriter.hh
index f6ebc6a5c2b70afe66f02ffbcffef8e1ebf2850c..522d4723c4c9409d36f2f26fabb32771f7a25674 100644
--- a/dune/vtk/writers/vtkstructuredgridwriter.hh
+++ b/dune/vtk/writers/vtkstructuredgridwriter.hh
@@ -37,12 +37,12 @@ namespace Dune
 
   private:
     /// Write a serial VTK file in Unstructured format
-    virtual void writeSerialFile (std::string const& filename) const override;
+    virtual void writeSerialFile (std::ofstream& out) const override;
 
     /// Write a parallel VTK file `pfilename.pvtu` in Unstructured format,
     /// with `size` the number of pieces and serial files given by `pfilename_p[i].vtu`
     /// for [i] in [0,...,size).
-    virtual void writeParallelFile (std::string const& pfilename, int size) const override;
+    virtual void writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const override;
 
     virtual std::string fileExtension () const override
     {
diff --git a/dune/vtk/writers/vtkstructuredgridwriter.impl.hh b/dune/vtk/writers/vtkstructuredgridwriter.impl.hh
index 1dcd7241622c62d7b0649dd828a31fa17bfe1c13..30e63238e681bc64982eb385e5673265ba5eed6c 100644
--- a/dune/vtk/writers/vtkstructuredgridwriter.impl.hh
+++ b/dune/vtk/writers/vtkstructuredgridwriter.impl.hh
@@ -18,17 +18,8 @@ namespace Dune {
 
 template <class GV, class DC>
 void VtkStructuredGridWriter<GV,DC>
-  ::writeSerialFile (std::string const& filename) const
+  ::writeSerialFile (std::ofstream& out) const
 {
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-  if (format_ == Vtk::ASCII) {
-    if (datatype_ == Vtk::FLOAT32)
-      out << std::setprecision(std::numeric_limits<float>::digits10+2);
-    else
-      out << std::setprecision(std::numeric_limits<double>::digits10+2);
-  }
-
   std::vector<pos_type> offsets; // pos => offset
   out << "<VTKFile"
       << " type=\"StructuredGrid\""
@@ -72,12 +63,8 @@ void VtkStructuredGridWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkStructuredGridWriter<GV,DC>
-  ::writeParallelFile (std::string const& pfilename, int /*size*/) const
+  ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int /*size*/) const
 {
-  std::string filename = pfilename + ".p" + this->fileExtension();
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
   out << "<VTKFile"
       << " type=\"PStructuredGrid\""
       << " version=\"1.0\""
diff --git a/dune/vtk/writers/vtkunstructuredgridwriter.hh b/dune/vtk/writers/vtkunstructuredgridwriter.hh
index 2429214253eda0c0986ad2b935426e39a697a504..fb2003fc1d02ba74f9af238b0e4a6f200848233d 100644
--- a/dune/vtk/writers/vtkunstructuredgridwriter.hh
+++ b/dune/vtk/writers/vtkunstructuredgridwriter.hh
@@ -39,12 +39,12 @@ namespace Dune
 
   private:
     /// Write a serial VTK file in Unstructured format
-    virtual void writeSerialFile (std::string const& filename) const override;
+    virtual void writeSerialFile (std::ofstream& out) const override;
 
     /// Write a parallel VTK file `pfilename.pvtu` in Unstructured format,
     /// with `size` the number of pieces and serial files given by `pfilename_p[i].vtu`
     /// for [i] in [0,...,size).
-    virtual void writeParallelFile (std::string const& pfilename, int size) const override;
+    virtual void writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const override;
 
     /// Write a series of timesteps in one file
     /**
@@ -55,13 +55,14 @@ namespace Dune
      * \param blocks        A list of block sizes of the binary data stored in the files.
      *                      Order: (points, cells, pointdata[0], celldata[0], pointdata[1], celldata[1],...)
      **/
-    void writeTimeseriesSerialFile (std::string const& filename,
+    void writeTimeseriesSerialFile (std::ofstream& out,
                                     std::string const& filenameMesh,
                                     std::vector<std::pair<double, std::string>> const& timesteps,
                                     std::vector<std::uint64_t> const& blocks) const;
 
     /// Write parallel VTK file for series of timesteps
-    void writeTimeseriesParallelFile (std::string const& pfilename, int size,
+    void writeTimeseriesParallelFile (std::ofstream& out,
+                                      std::string const& pfilename, int size,
                                       std::vector<std::pair<double, std::string>> const& timesteps) const;
 
     virtual std::string fileExtension () const override
diff --git a/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh b/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
index 9bc44820d8741cb2729ab202fce3a3a6146d911b..0a4e8b703414d397d2d98b16ee4c413a244c956b 100644
--- a/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
+++ b/dune/vtk/writers/vtkunstructuredgridwriter.impl.hh
@@ -18,18 +18,8 @@ namespace Dune {
 
 template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
-  ::writeSerialFile (std::string const& filename) const
+  ::writeSerialFile (std::ofstream& out) const
 {
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
-  if (format_ == Vtk::ASCII) {
-    if (datatype_ == Vtk::FLOAT32)
-      out << std::setprecision(std::numeric_limits<float>::digits10+2);
-    else
-      out << std::setprecision(std::numeric_limits<double>::digits10+2);
-  }
-
   std::vector<pos_type> offsets; // pos => offset
   out << "<VTKFile"
       << " type=\"UnstructuredGrid\""
@@ -77,12 +67,8 @@ void VtkUnstructuredGridWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
-  ::writeParallelFile (std::string const& pfilename, int size) const
+  ::writeParallelFile (std::ofstream& out, std::string const& pfilename, int size) const
 {
-  std::string filename = pfilename + ".pvtu";
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
   out << "<VTKFile"
       << " type=\"PUnstructuredGrid\""
       << " version=\"1.0\""
@@ -136,19 +122,12 @@ void VtkUnstructuredGridWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
-  ::writeTimeseriesSerialFile (std::string const& filename,
+  ::writeTimeseriesSerialFile (std::ofstream& out,
                                std::string const& filenameMesh,
                                std::vector<std::pair<double, std::string>> const& timesteps,
                                std::vector<std::uint64_t> const& blocks) const
 {
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
   assert(is_a(format_, Vtk::APPENDED));
-  if (datatype_ == Vtk::FLOAT32)
-    out << std::setprecision(std::numeric_limits<float>::digits10+2);
-  else
-    out << std::setprecision(std::numeric_limits<double>::digits10+2);
 
   std::vector<std::vector<pos_type>> offsets(timesteps.size()); // pos => offset
   out << "<VTKFile"
@@ -253,12 +232,11 @@ void VtkUnstructuredGridWriter<GV,DC>
 
 template <class GV, class DC>
 void VtkUnstructuredGridWriter<GV,DC>
-  ::writeTimeseriesParallelFile (std::string const& pfilename, int size, std::vector<std::pair<double, std::string>> const& timesteps) const
+  ::writeTimeseriesParallelFile (std::ofstream& out,
+                                 std::string const& pfilename,
+                                 int size,
+                                 std::vector<std::pair<double, std::string>> const& timesteps) const
 {
-  std::string filename = pfilename + ".pvtu";
-  std::ofstream out(filename, std::ios_base::ate | std::ios::binary);
-  assert(out.is_open());
-
   out << "<VTKFile"
       << " type=\"PUnstructuredGrid\""
       << " version=\"1.0\""