C++ Structure: How do I write a structure to a file?


/ Published in: C++
Save to your folder(s)

Q: How do I write a structure to a file?

A: You can easily write a structure to a file as long as the structure is what is known as a POD (Plain Old Data) type. This means that all members of the structure must be of a fixed size, which implies that the structure can not contain pointers. This stipulation goes for all members of the structure. Look at these examples:


Copy this code and paste it in your HTML
  1. struct a
  2. {
  3. int x;
  4. float f;
  5. double d;
  6. char c;
  7. char s[50];
  8. };
  9.  
  10. // OK
  11.  
  12. struct b
  13. {
  14. int x;
  15. float f;
  16. double d;
  17. char c;
  18. char* s;
  19. };
  20.  
  21. // Wrong! 's' has unknown length; only address of pointer will be written.
  22.  
  23.  
  24. struct c
  25. {
  26. int x;
  27. float f;
  28. double d;
  29. char c;
  30.  
  31. struct
  32. {
  33. char* s;
  34. } e;
  35. };
  36.  
  37. // Wrong! 'e' has a char* member.
  38. // So, now hopefully you have a POD data type. We will use 'fstream' to read and write it:
  39.  
  40. //Code:
  41.  
  42. #include <string>
  43. #include <fstream>
  44.  
  45. struct s
  46. {
  47. // Your POD data here
  48. };
  49.  
  50. void write(const std::string& file_name, s& data)
  51. {
  52. std::ofstream out(file_name.c_str());
  53. out.write(reinterpret_cast<char*>(&s), sizeof(s));
  54. }
  55.  
  56. void read(const std::string& file_name, s& data)
  57. {
  58. std::ifstream in(file_name.c_str());
  59. in.read(reinterpret_cast<char*>(&s), sizeof(s));
  60. }
  61.  
  62. int main()
  63. {
  64. s myStruct;
  65. read("test.dat", myStruct);
  66. write("test.dat", myStruct);
  67. }
  68. /*
  69. This code works fine, but only works for a single type and it not for an array. To make this solution more flexible, we'll define a template function that will work for any POD structure.
  70. */
  71.  
  72. template<typename T>
  73. void write_pod(std::ofstream& out, T& t)
  74. {
  75. out.write(reinterpret_cast<char*>(&t), sizeof(T));
  76. }
  77.  
  78. template<typename T>
  79. void read_pod(std::ifstream& in, T& t)
  80. {
  81. in.read(reinterpret_cast<char*>(&t), sizeof(T));
  82. }
  83.  
  84. /*Now we have two simple functions that will write and read an arbitrary POD structure. Now, we can easily apply them to our current example, but instead, I will show you how they can be used to write an array to a file. To make this easy, we will make use of the STL algorithm 'for_each' to write.*/
  85.  
  86.  
  87. #include <vector>
  88. #include <fstream>
  89. #include <algorithm>
  90.  
  91. int main()
  92. {
  93. std::vector<s> myStructs;
  94. std::ofstream out("test.dat");
  95.  
  96. // Fill vector here
  97. std::for_each(myStructs.begin(), myStructs.end(), std::bind1st(write_pod<s>, out));
  98. }
  99.  
  100. //or for an array
  101.  
  102. #include <fstream>
  103. #include <algorithm>
  104.  
  105. int main()
  106. {
  107. s myStructs[20];
  108. std::ofstream out("test.dat");
  109.  
  110. // Fill array here
  111. std::for_each(myStructs, myStructs + 20, std::bind1st(write_pod<s>, out));
  112. }
  113.  
  114. /*This code works great for writing, but posses a problem when reading; we don't know the size of the array. This is not always a problem - we can just read until we hit the end of the file. But if you need to allocate an array, or want to store several different structs in one file this will not work. It also allows us to optimize our code with 'vector' by presizing the 'vector' before reading. This is a fairly simple fix, we will just write the size before all of our data:*/
  115.  
  116.  
  117. #include <vector>
  118. #include <fstream>
  119. #include <algorithm>
  120.  
  121. int main()
  122. {
  123. std::vector<s> myStructs;
  124. std::ofstream out("test.dat");
  125.  
  126. // Fill vector here
  127. write_pod<long>(out, myStructs.size());
  128. std::for_each(myStructs.begin(), myStructs.end(), std::bind1st(write_pod<s>, out));
  129. }
  130.  
  131. /*Notice, that 'write_pod()' can also be used with integral types since they are POD's themselves. Unfortunately, the STL does not have an algorithm that allows us to easily read from a 'vector' into a file. So, we will just use a loop. Here is the method to read a 'vector' of structs from a file, I will templatize it to begin with:*/
  132.  
  133.  
  134. #include <vector>
  135. #include <fstream>
  136.  
  137. template<typename T>
  138. void read_pod_vector(std::ifstream& in, std::vector<T>& vect)
  139. {
  140. long size;
  141.  
  142. read_pod(in, size);
  143. vect.resize(size);
  144.  
  145. for(int i = 0;i < size;++i)
  146. {
  147. T t;
  148. read_pod(in, t);
  149. vect.push_back(t);
  150. }
  151. }
  152.  
  153. //While we're at it, we might as well define a similar function to write a 'vector':
  154.  
  155. #include <vector>
  156. #include <fstream>
  157. #include <algorithm>
  158.  
  159. template<typename T>
  160. void write_pod_vector(std::ofstream& out, std::vector<T>& vect)
  161. {
  162. write_pod<long>(out, vect.size());
  163. std::for_each(vect.begin(), vect.end(), std::bind1st(write_pod<T>, out));
  164. }
  165.  
  166. So, implementing these functions to read and write a 'vector' we have:
  167.  
  168. Code:
  169.  
  170. #include <vector>
  171. #include <fstream>
  172.  
  173. int main()
  174. {
  175. std::vector&lts> myStructs;
  176. std::ofstream out("test.dat");
  177. std::ifstream in("test.dat");
  178.  
  179. // Fill vector here
  180. write_pod_vector(out, myStructs);
  181. out.close();
  182. read_pod_vector(in, myStructs);
  183. }
  184.  
  185. /*So, now you know how to write a POD structure, or a set of POD structures to a file. What if your structure is not POD? Well, then it becomes a bit more complicated. The approach you would take is the exact same as we took with 'vector', after all 'vector' is a non-POD type and we are writing it to a file. That is, you would write the size of the data before the data so you know how much data to read. You may have noticed that the second parameter to read/write is the size of the data, so you don't need loop through all of your data. I will show you now examples that use this fact:*/
  186.  
  187.  
  188. #include <vector>
  189. #include <fstream>
  190.  
  191. template<typename T>
  192. void write_pod_vector(std::ofstream& out, std::vector<T>& vect)
  193. {
  194. long size = myStructs.size();
  195. write_pod<long>(out, size);
  196. out.write(reinterpret_cast<char*>(vect.front()), size * sizeof(T));
  197. }
  198.  
  199. /*This example takes advantage of vector's congenious structure and second parameter to write which allows us to write the entire 'vector' with one call. We can do the same thing to read:*/
  200.  
  201.  
  202. #include <vector>
  203. #include <fstream>
  204.  
  205. template<typename T>
  206. void read_pod_vector(std::ifstream& in, std::vector<T>& vect)
  207. {
  208. long size;
  209. read_pod(in, size);
  210. vect.resize(size);
  211. in.read(reinterpret_cast<char*>(vect.front()), size * sizeof(T));
  212. }
  213.  
  214. /*Not only do we cut out several lines, but we make our program more effient. My next example will show you to read/write other pointer data. The following structure is used to store a variable length string:*/
  215.  
  216.  
  217. struct str
  218. {
  219. long size;
  220. char* s;
  221. };
  222.  
  223. //Now, here are the read an write methods for this structure.
  224.  
  225. #include <fstream>
  226.  
  227. void write_str( std::ofstream& out, str& s )
  228. {
  229. out.write(reinterpret_cast<char*>(&s.size), sizeof(long));
  230. out.write(s.s, s.size * sizeof(char));
  231. }
  232.  
  233. void read_str(std::ifstream& in, str& s)
  234. {
  235. in.read(reinterpret_cast<char*>(&s.size), sizeof(long));
  236. s.s = new char[s.size];
  237. in.read(s.s, s.size * sizeof(char));
  238. }

URL: http://www.codeguru.com/forum/showthread.php?t=269648

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.