diff --git a/regtest/rt17/COLVAR.reference b/regtest/rt17/COLVAR.reference
index ed31025d8d38411a7c1f932d9e7d1569c9f28bae..d309dca201be6e93d48619bd246e25c4c6a50cf8 100644
--- a/regtest/rt17/COLVAR.reference
+++ b/regtest/rt17/COLVAR.reference
@@ -1,6 +1,8 @@
-#! FIELDS time d1.x d2 d3
+#! FIELDS time d1.x
  0.000000  8.126
+#! FIELDS time d2
  0.500000 27.263
  1.000000 27.786
+#! FIELDS time d3
  1.500000 21.565
  2.000000 21.329
diff --git a/src/GenericPrint.cpp b/src/GenericPrint.cpp
index aabee48899ebe79e1a54f0617f977c6b0ddecb7e..84fed22910803e1b9737f7d6868a37dc55829514 100644
--- a/src/GenericPrint.cpp
+++ b/src/GenericPrint.cpp
@@ -56,8 +56,10 @@ public ActionPilot,
 public ActionWithArguments
 {
   string file;
-  FILE* fp;
+  PlumedOFile ofile;
   string fmt;
+// small internal utility
+  void updateFields();
 /////////////////////////////////////////
 // these are crazy things just for debug:
 // they allow to change regularly the
@@ -94,27 +96,22 @@ GenericPrint::GenericPrint(const ActionOptions&ao):
 Action(ao),
 ActionPilot(ao),
 ActionWithArguments(ao),
-fp(NULL),
 fmt("%f"),
 rotate(0)
 {
   parse("FILE",file);
   if(file.length()>0){
-    if(comm.Get_rank()==0){
-      fp=fopen(file.c_str(),"a");
-      log.printf("  on file %s\n",file.c_str());
-      fprintf(fp,"#! FIELDS time");
-      for(unsigned i=0;i<getNumberOfArguments();i++){
-        fprintf(fp," %s",getPntrToArgument(i)->getName().c_str());
-      };
-      fprintf(fp,"\n");
-    }
+    ofile.open(file.c_str(),"wa");
+    log.printf("  on file %s\n",file.c_str());
   } else {
     log.printf("  on plumed log file\n");
+    ofile.link(log);
   }
+  updateFields();
   parse("FMT",fmt);
   fmt=" "+fmt;
   log.printf("  with format %s\n",fmt.c_str());
+  ofile.fmtFields(fmt);
 /////////////////////////////////////////
 // these are crazy things just for debug:
 // they allow to change regularly the
@@ -126,6 +123,7 @@ rotate(0)
     vector<Value*> a(1,rotateArguments[0]);
     requestArguments(vector<Value*>(1,rotateArguments[0]));
     rotateLast=0;
+    updateFields();
   }
 /////////////////////////////////////////
   checkRead();
@@ -143,30 +141,30 @@ void GenericPrint::prepare(){
       rotateLast++;
       rotateLast%=rotateArguments.size();
       requestArguments(vector<Value*>(1,rotateArguments[rotateLast]));
+      updateFields();
     }
   }
 /////////////////////////////////////////
 }
 
 void GenericPrint::update(){
-    if(comm.Get_rank()!=0)return;
-    if(!fp){
-      log.printf("PRINT:");
-      for(unsigned i=0;i<getNumberOfArguments();i++){
-        log.printf(fmt.c_str(),getArgument(i));
-      };
-      log.printf("\n");
-    } else {
-      fprintf(fp," %f",getTime());
+      ofile.printField("time",getTime());
       for(unsigned i=0;i<getNumberOfArguments();i++){
-        fprintf(fp,fmt.c_str(),getArgument(i));
+        ofile.printField(getPntrToArgument(i)->getName(),getArgument(i));
       };
-      fprintf(fp,"\n");
-    }
+      ofile.printField();
 }
 
 GenericPrint::~GenericPrint(){
-  if(fp) fclose(fp);
+}
+
+void GenericPrint::updateFields(){
+  ofile.clearFields();
+  ofile.addField("time");
+  ofile.fmtField("time"," %f");
+  for(unsigned i=0;i<getNumberOfArguments();i++){
+    ofile.addField(getPntrToArgument(i)->getName());
+  }
 }
 
 }
diff --git a/src/Log.cpp b/src/Log.cpp
index 40354c5eb0713709d79561b18412f067c5f89649..17f88dce8cdb3c8cfeb79487505f78d34993ed1c 100644
--- a/src/Log.cpp
+++ b/src/Log.cpp
@@ -19,62 +19,5 @@
    You should have received a copy of the GNU Lesser General Public License
    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include <cstdarg>
-#include <cstring>
 #include "Log.h"
-#include "PlumedCommunicator.h"
-#include "PlumedException.h"
-
-using namespace std;
-using namespace PLMD;
-
-int Log::printf(const char*fmt,...){
-  if(comm.Get_rank()>0)return 0;
-  int pointer=strlen(buffer);
-  va_list arg;
-  va_start(arg, fmt);
-  int r=vsnprintf(&buffer[pointer],buflen-pointer,fmt,arg);
-  va_end(arg);
-  plumed_massert(r>-1 && r<buflen-pointer,"error using fmt string " + std::string(fmt));
-
-// Line is buffered until newline, then written with a PLUMED: prefix
-  char*p1=buffer;
-  char*p2;
-  while((p2=strchr(p1,'\n'))){
-    *p2='\0';
-    fprintf(fp,"PLUMED: %s\n",p1);
-    p1=p2+1;
-  };
-  memmove(buffer,p1,strlen(p1)+1);
-  return r;
-}
-
-Log::Log(PlumedCommunicator &comm):
-  fp(stdout),
-  toBeClosed(false),
-  comm(comm){
-  buffer=new char[buflen];
-  for(int i=0;i<buflen;i++) buffer[i]='\0';
-}
-
-Log::~Log(){
-  if(comm.Get_rank()>0)return;
-  if(!fp && toBeClosed)fclose(fp);
-  delete [] buffer;
-}
-
-void Log::setFile(string str){
-  if(comm.Get_rank()>0)return;
-  fp=fopen(str.c_str(),"w");
-  toBeClosed=true;
-}
-
-void Log::set(FILE*f){
-  if(comm.Get_rank()>0)return;
-  fp=f;
-}
-
-void Log::flush(){
-  fflush(fp);
-}
 
diff --git a/src/Log.h b/src/Log.h
index a2a155c93a87ca993b691e55fdfd8f7c1e75921a..b112c01649e3a29f2876cfe7db754fd50642981c 100644
--- a/src/Log.h
+++ b/src/Log.h
@@ -26,6 +26,8 @@
 #include <string>
 #include <sstream>
 
+#include "PlumedFile.h"
+
 namespace PLMD{
 
 class PlumedCommunicator;
@@ -36,42 +38,11 @@ class PlumedCommunicator;
 /// also to write with a << operator. Moreover, it can prefix
 /// lines with the "PLUMED:" prefix, useful to grep out plumed
 /// log from output
-class Log
+class Log :
+  public PlumedOFile
 {
-/// Actual FILE stream
-  FILE* fp;
-/// Flag to know if, when Log is destructed, file should be closed
-  bool toBeClosed;
-  static const int buflen=10000;
-  std::ostringstream oss;
-  char* buffer;
-/// Communicator (to write only with the first processor)
-  PlumedCommunicator& comm;
-public:
-/// Initialize on a given communicator
-  Log(PlumedCommunicator&);
-  ~Log();
-/// Set a file with a specific name
-  void setFile(std::string str);
-/// Link to an already open FILE stream
-  void set(FILE*f);
-  void flush();
-/// Standard printf-like function
-  int printf(const char*fmt,...);
-  template <class T>
-  friend Log& operator<<(Log&,const T &);
 };
 
-/// Write using << syntax
-template <class T>
-Log& operator<<(Log&log,const T &t){
-  log.oss<<t;
-  log.printf("%s",log.oss.str().c_str());
-  log.oss.str("");
-  return log;
-}
-
-
 }
 
 #endif
diff --git a/src/PlumedFile.cpp b/src/PlumedFile.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c7088a2a928b926f7306362f19dfd6fcacf83249
--- /dev/null
+++ b/src/PlumedFile.cpp
@@ -0,0 +1,276 @@
+#include "PlumedFile.h"
+#include "PlumedException.h"
+#include "Action.h"
+#include "PlumedMain.h"
+#include "PlumedCommunicator.h"
+#include <cstdarg>
+#include <cstring>
+
+using namespace PLMD;
+
+void PlumedFileBase::test(){
+  PLMD::PlumedOFile pof;
+  pof.open("ciao","w");
+  pof.printf("%s\n","test1");
+  pof.setLinePrefix("plumed: ");
+  pof.printf("%s\n","test2");
+  pof.addField("x1");
+  pof.addField("x2",67.0);
+  pof.addField("x3");
+  pof.printField("x1",10.0).printField("x3",20.12345678901234567890).printField();
+  pof.printField("x1",10.0).printField("x3",-1e70*20.12345678901234567890).printField();
+  pof.printField("x3",10.0).printField("x2",777).printField("x1",-1e70*20.12345678901234567890).printField();
+  pof.printField("x3",67.0).printField("x1",18.0).printField();
+  pof.close();
+
+  PLMD::PlumedIFile pif;
+  std::string s;
+  pif.open("ciao","r");
+  pif.getline(s); std::printf("%s\n",s.c_str());
+  pif.getline(s); std::printf("%s\n",s.c_str());
+  pif.close();
+}
+
+size_t PlumedOFile::llwrite(const char*ptr,size_t s){
+  size_t r;
+  if(fp){
+    if(! (comm && comm->Get_rank()>0)){
+      r=fwrite(ptr,1,s,fp);
+    }
+    if(comm) comm->Bcast(&r,1,0);
+  } else if(linked){
+    (*linked)<<ptr;
+    r=strlen(ptr);
+  } else plumed_merror("writing on uninitilized PlumedFile");
+  return r;
+}
+
+size_t PlumedIFile::llread(char*ptr,size_t s){
+  plumed_assert(fp);
+  size_t r;
+  if(! (comm && comm->Get_rank()>0)){
+    r=fread(ptr,1,s,fp);
+  }
+  if(comm) comm->Bcast(&r,1,0);
+  if(comm) comm->Bcast(ptr,r,0);
+  return r;
+}
+
+PlumedFileBase& PlumedFileBase::link(FILE*fp){
+  this->fp=fp;
+  cloned=true;
+  return *this;
+}
+
+PlumedFileBase& PlumedFileBase::flush(){
+  fflush(fp);
+  return *this;
+}
+
+PlumedFileBase& PlumedFileBase::link(PlumedCommunicator&comm){
+  this->comm=&comm;
+  return *this;
+}
+
+PlumedFileBase& PlumedFileBase::link(PlumedMain&plumed){
+  this->plumed=&plumed;
+  link(plumed.comm);
+  return *this;
+}
+
+PlumedFileBase& PlumedFileBase::link(Action&action){
+  this->action=&action;
+  link(action.plumed);
+  return *this;
+}
+
+PlumedFileBase& PlumedFileBase::open(const std::string& path,const std::string& mode){
+  plumed_assert(!cloned);
+  fp=NULL;
+  if(plumed){
+    const std::string pathsuf=path+plumed->getSuffix();
+    fp=std::fopen(const_cast<char*>(pathsuf.c_str()),const_cast<char*>(mode.c_str()));
+  }
+  if(!fp) fp=std::fopen(const_cast<char*>(path.c_str()),const_cast<char*>(mode.c_str()));
+  plumed_massert(fp,"file " + path + "cannot be found");
+  return *this;
+}
+
+void        PlumedFileBase::close(){
+  plumed_assert(!cloned);
+  std::fclose(fp);
+  fp=NULL;
+}
+
+PlumedFileBase::PlumedFileBase():
+  fp(NULL),
+  comm(NULL),
+  plumed(NULL),
+  action(NULL),
+  cloned(false)
+{
+}
+
+PlumedFileBase::~PlumedFileBase()
+{
+  if(!cloned) fclose(fp);
+}
+
+PlumedOFile::PlumedOFile():
+  linked(NULL),
+  fieldChanged(false),
+  fieldFmt("%22.16lg")
+{
+  buffer=new char[buflen];
+}
+
+PlumedOFile::~PlumedOFile(){
+  delete [] buffer;
+}
+
+PlumedOFile& PlumedOFile::link(PlumedOFile&l){
+  fp=NULL;
+  linked=&l;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::setLinePrefix(const std::string&l){
+  linePrefix=l;
+  return *this;
+}
+
+int PlumedOFile::printf(const char*fmt,...){
+  int pointer=strlen(buffer);
+  va_list arg;
+  va_start(arg, fmt);
+  int r=std::vsnprintf(&buffer[pointer],buflen-pointer,fmt,arg);
+  va_end(arg);
+  plumed_massert(r>-1 && r<buflen-pointer,"error using fmt string " + std::string(fmt));
+
+// Line is buffered until newline, then written with a PLUMED: prefix
+  char*p1=buffer;
+  char*p2;
+  while((p2=strchr(p1,'\n'))){
+    *p2='\0';
+    if(linePrefix.length()>0) llwrite(linePrefix.c_str(),linePrefix.length());
+    llwrite(p1,std::strlen(p1));
+    llwrite("\n",1);
+    p1=p2+1;
+  };
+  memmove(buffer,p1,strlen(p1)+1);
+  return r;
+}
+
+PlumedOFile& PlumedOFile::addField(const std::string&name){
+  Field f;
+  f.name=name;
+  fields.push_back(f);
+  fieldChanged=true;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::addField(const std::string&name,double v){
+  Field f;
+  f.name=name;
+  f.value=v;
+  f.constant=true;
+  f.set=true;
+  fields.push_back(f);
+  fieldChanged=true;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::clearFields(){
+  fields.clear();
+  fieldChanged=true;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::fmtFields(const std::string&fmt){
+  fieldFmt=fmt;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::fmtField(const std::string&name,const std::string&fmt){
+  unsigned i;
+  for(i=0;i<fields.size();i++) if(fields[i].name==name) break;
+  plumed_assert(i<fields.size());
+  fields[i].fmt=fmt;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::printField(const std::string&name,double v){
+  unsigned i;
+  for(i=0;i<fields.size();i++) if(fields[i].name==name) break;
+  plumed_assert(i<fields.size());
+  if(fields[i].constant) fieldChanged=true;
+  fields[i].value=v;
+  fields[i].set=true;
+  return *this;
+}
+
+PlumedOFile& PlumedOFile::printField(){
+  if(fieldChanged){
+    printf("#! FIELDS");
+    for(unsigned i=0;i<fields.size();i++){
+      printf(" %s",fields[i].name.c_str());
+    }
+    printf("\n");
+    for(unsigned i=0;i<fields.size();i++)
+      if(fields[i].constant){
+        std::string fmt;
+        if(fields[i].fmt.length()>0) fmt=fields[i].fmt;
+        else fmt=fieldFmt;
+        printf("#! SET %s ",fields[i].name.c_str());
+        printf(fmt.c_str(),fields[i].value);
+        printf("\n");
+    }
+  }
+  fieldChanged=false;
+  for(unsigned i=0;i<fields.size();i++){
+    plumed_assert(fields[i].set);
+    if(!fields[i].constant){
+      std::string fmt;
+      if(fields[i].fmt.length()>0) fmt=fields[i].fmt;
+      else fmt=fieldFmt;
+//      printf(" ");
+      printf(fmt.c_str(),fields[i].value);
+      fields[i].set=false;
+    }
+  }
+  printf("\n");
+  return *this;
+}
+
+PlumedIFile& PlumedIFile::scanFieldList(std::vector<std::string>&s){
+  s=fields;
+  return *this;
+}
+
+PlumedIFile& PlumedIFile::scanField(const std::string&,double&){
+  plumed_error();
+  return *this;
+}
+
+PlumedIFile& PlumedIFile::scanField(){
+  plumed_error();
+  return *this;
+}
+
+PlumedIFile::PlumedIFile(){
+}
+
+PlumedIFile::~PlumedIFile(){
+}
+
+PlumedIFile& PlumedIFile::getline(std::string &str){
+  char tmp;
+  str="";
+  while(llread(&tmp,1)==1 && tmp && tmp!='\n'){
+    str+=tmp;
+  }
+  return *this;
+}
+
+
+
diff --git a/src/PlumedFile.h b/src/PlumedFile.h
new file mode 100644
index 0000000000000000000000000000000000000000..c6ebf120fbf7b7fc8c256deb96dd5037d6c5c2ed
--- /dev/null
+++ b/src/PlumedFile.h
@@ -0,0 +1,116 @@
+#ifndef __PLUMED_PlumedFile_h
+#define __PLUMED_PlumedFile_h
+
+#include <cstdio>
+#include <vector>
+#include <string>
+#include <sstream>
+
+namespace PLMD{
+
+class PlumedCommunicator;
+class PlumedMain;
+class Action;
+
+class PlumedFileBase{
+protected:
+  class FieldBase{
+  public:
+    std::string name;
+    double value;
+    bool constant;
+    FieldBase(): value(0.0),constant(false){}
+  };
+
+  static const int buflen=10000;
+  FILE* fp;
+  PlumedCommunicator* comm;
+  PlumedMain* plumed;
+  Action* action;
+  bool cloned;
+  PlumedFileBase();
+public:
+  PlumedFileBase& link(FILE*);
+  PlumedFileBase& link(PlumedMain&);
+  PlumedFileBase& link(PlumedCommunicator&);
+  PlumedFileBase& link(Action&);
+  PlumedFileBase& flush();
+  PlumedFileBase& open(const std::string&name,const std::string& mode);
+  void        close();
+  virtual ~PlumedFileBase();
+  static void test();
+};
+
+class PlumedOFile:
+public virtual PlumedFileBase{
+  PlumedOFile* linked;
+  char* buffer;
+  class Field:
+  public FieldBase{
+  public:
+    bool set;
+    std::string fmt;
+    Field(): set(false) {}
+  };
+  size_t llwrite(const char*,size_t);
+  bool fieldChanged;
+  std::string fieldFmt;
+  std::vector<Field> fields;
+  std::string linePrefix;
+  std::ostringstream oss;
+public:
+  PlumedOFile();
+  ~PlumedOFile();
+  using PlumedFileBase::link;
+  PlumedOFile& link(PlumedOFile&);
+  PlumedOFile& setLinePrefix(const std::string&);
+  PlumedOFile& addField(const std::string&);
+  PlumedOFile& addField(const std::string&,double);
+  PlumedOFile& clearFields();
+  PlumedOFile& fmtFields(const std::string&);
+  PlumedOFile& fmtField(const std::string&,const std::string&);
+  PlumedOFile& printField(const std::string&,double);
+  PlumedOFile& printField();
+  int printf(const char*fmt,...);
+  template <class T>
+  friend PlumedOFile& operator<<(PlumedOFile&,const T &);
+};
+
+class PlumedIFile:
+public virtual PlumedFileBase{
+  class Field:
+  public FieldBase{
+  public:
+    bool read;
+    Field(): read(false) {}
+  };
+  size_t llread(char*,size_t);
+  std::vector<std::string> fields;
+public:
+  PlumedIFile();
+  ~PlumedIFile();
+  PlumedIFile& scanFieldList(std::vector<std::string>&);
+  PlumedIFile& scanField(const std::string&,double&);
+  PlumedIFile& scanField();
+  PlumedIFile& getline(std::string&);
+};
+
+class PlumedFile:
+public PlumedOFile,
+public PlumedIFile
+{
+};
+
+/// Write using << syntax
+template <class T>
+PlumedOFile& operator<<(PlumedOFile&of,const T &t){
+  of.oss<<t;
+  of.printf("%s",of.oss.str().c_str());
+  of.oss.str("");
+  return of;
+}
+
+
+}
+
+#endif
diff --git a/src/PlumedMain.cpp b/src/PlumedMain.cpp
index a55e712aee636e72331525aa38561a9b3454739f..29ec7d53a42be9ba59714269a6e21f3f424b06a8 100644
--- a/src/PlumedMain.cpp
+++ b/src/PlumedMain.cpp
@@ -53,7 +53,7 @@ PlumedMain::PlumedMain():
   stopwatch(*new Stopwatch),
   grex(NULL),
   initialized(false),
-  log(*new Log(comm)),
+  log(*new Log),
   citations(*new Citations),
   step(0),
   active(false),
@@ -62,6 +62,9 @@ PlumedMain::PlumedMain():
   bias(0.0),
   novirial(false)
 {
+  log.link(comm);
+  log.setLinePrefix("PLUMED: ");
+  log.link(stdout);
   stopwatch.start();
   stopwatch.pause();
 }
@@ -260,11 +263,11 @@ void PlumedMain::cmd(const std::string & word,void*val){
        MDEngine=static_cast<char*>(val);
   } else if(word=="setLog"){
        CHECK_NOTINIT(initialized,word);
-       log.set(static_cast<FILE*>(val));
+       log.link(static_cast<FILE*>(val));
   } else if(word=="setLogFile"){
        CHECK_NOTINIT(initialized,word);
        CHECK_NULL(val,word);
-       log.setFile(static_cast<char*>(val));
+       log.open(static_cast<char*>(val),"w");
   } else if(word=="getExchangesFlag"){
        CHECK_INIT(initialized,word);
        CHECK_NULL(val,word);