IMP  2.0.0
The Integrative Modeling Platform
base/file.h
Go to the documentation of this file.
1 /**
2  * \file IMP/base/file.h
3  * \brief Handling of file input/output
4  *
5  * Copyright 2007-2013 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPBASE_FILE_H
10 #define IMPBASE_FILE_H
11 
12 #include <IMP/base/base_config.h>
13 #include "base_macros.h"
14 #include "exception.h"
15 #include "internal/ifile.h"
16 #include "Pointer.h"
17 #include "InputAdaptor.h"
18 #include <boost/shared_ptr.hpp>
19 #include <fstream>
20 #include <iostream>
21 
22 IMPBASE_BEGIN_NAMESPACE
23 
24 #if !defined(IMP_DOXYGEN)
25 template <class Stream>
26 struct TextProxy {
27  Stream *str_;
28  OwnerPointer<Object> ptr_;
29  TextProxy(Stream *str, Object *ptr): str_(str), ptr_(ptr){}
30 };
31 #endif
32 
33 
34 /** A TextOutput can be implicitly constructed from a C++ stream, a
35  Python filelike object or a path to a file. As a result, those can be
36  passed directly to functions which take a TextOutput as an
37  argument.
38 
39  Files are created lazily, so TextOutput can be passed as
40  arguments to functions that might not produce output.
41  \code
42  IMP::atom::write_pdb(particles, "path/to/file.pdb");
43  IMP::atom::write_pdb(particles, my_fstream);
44  \endcode
45  \see TextInput
46 */
47 class IMPBASEEXPORT TextOutput: public InputAdaptor
48 {
49  boost::shared_ptr<internal::IOStorage<std::ostream> > out_;
50  public:
51 #ifndef IMP_DOXYGEN
52  // SWIG needs these here for some bizarre reason
53  TextOutput(int);
54  TextOutput(double);
55  TextOutput(const char *c, bool append=false);
56  TextOutput(TextProxy<std::ostream> p);
57 #endif
58  TextOutput(){}
59  TextOutput(std::string file_name, bool append=false);
60 #ifndef SWIG
61  TextOutput(std::ostream &out, std::string name="C++ stream");
62 #endif
63 
64 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
65  operator std::ostream &() {
66  return get_stream();
67  }
68  IMP_SAFE_BOOL(TextOutput, out_ && out_->get_stream());
69  std::ostream &get_stream() {
70  IMP_USAGE_CHECK(out_, "Attempting to write to uninitialized text input");
71  return out_->get_stream();
72  }
73 #endif
74  IMP_SHOWABLE_INLINE(TextOutput, out << get_name());
75  std::string get_name() const {
76  return out_->get_name();
77  }
78 };
79 
80 
81 /** A TextInput can be implicitly constructed from a C++ stream, a
82  Python filelike object or a path to a file. As a result, those can be
83  passed directly to functions which take a TextInput as an
84  argument.
85  \code
86  IMP::atom::read_pdb("path/to/file.pdb", m);
87  IMP::atom::read_pdb(my_fstream, m);
88  \endcode
89  \see TextOutput
90 */
91 class IMPBASEEXPORT TextInput: public InputAdaptor
92 {
93  boost::shared_ptr<internal::IOStorage<std::istream> > in_;
94  public:
95 #ifndef IMP_DOXYGEN
96  // SWIG needs these here for some bizarre reason
97  TextInput(int);
98  TextInput(double);
99  TextInput(const char *c);
100  TextInput(TextProxy<std::istream> p);
101 #endif
102  TextInput(){}
103  TextInput(std::string file_name);
104 #ifndef SWIG
105  TextInput(std::istream &out, std::string name="C++ stream");
106 #endif
107 
108 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
109  operator std::istream &() {
110  return get_stream();
111  }
112  std::istream &get_stream() {
113  if (!in_) {
114  IMP_THROW("Attempting to read from uninitialized text input",
115  IOException);
116  }
117  return in_->get_stream();
118  }
119 #endif
120  IMP_SHOWABLE_INLINE(TextInput, out << get_name());
121  IMP_SAFE_BOOL(TextInput, in_ && in_->get_stream());
122  std::string get_name() const {
123  return in_->get_name();
124  }
125 };
126 
127 //! Set the target for the log.
128 /** See TextOutput for options. Python users should use
129  SetLogTarget instead.
130  \ingroup logging
131  */
132 #ifndef SWIG
133 IMPBASEEXPORT void set_log_target(TextOutput l);
134 IMPBASEEXPORT TextOutput get_log_target();
135 #endif
136 
137 /** Set the log target to a given value and reset it
138  when the object is destroyed. Use this in Python
139  to set the target of logs.
140  \ingroup logging
141 */
142 class SetLogTarget: public base::RAII {
143  /* Python deletes all Python objects before static
144  destructors are called. As a result, having static
145  C++ objects point to Python objects is problematic.
146  This class makes sure that the pointer to the
147  Python class gets cleaned up when Python exits.
148  */
149  TextOutput old_;
150 public:
152  old_=get_log_target();,
153  set_log_target(to);,
154  set_log_target(old_);,);
155 };
156 
157 
160 
161 /** Create a temporary file. The path can be extracted from the TextOutput.
162 
163  If suffix is non-empty, there is some small chance of a collision on
164  non-BSD systems as a unique temporary file is first created, and then
165  a file with that suffix appended is created.*/
166 IMPBASEEXPORT TextOutput create_temporary_file(std::string prefix="imp_temp",
167  std::string suffix="");
168 
169 
170 /** Create a temporary file.
171 
172  If suffix is non-empty, there is some small chance of a collision on
173  non-BSD systems as a unique temporary file is first created, and then
174  a file with that suffix appended is created.*/
175 IMPBASEEXPORT std::string
176 create_temporary_file_name(std::string prefix="imp_temp",
177  std::string suffix="");
178 
179 
180 /** Return a path to a file relative to another file. For example
181  if base is path/to/config.file and relative is data/image0.jpg
182  then the return value would be path/to/data/image0.jpg. This
183  function should be used when processing configuration files so
184  that the meaning of the configuration file does not change if
185  current working directory changes.
186 */
187 IMPBASEEXPORT std::string get_relative_path(std::string base,
188  std::string relative);
189 
190 IMPBASE_END_NAMESPACE
191 
192 #endif /* IMPBASE_FILE_H */