Browse Source

[3669] It is now possible to reopen a CSV file and seek to its end.

Marcin Siodelski 10 years ago
parent
commit
550f8901c0
3 changed files with 47 additions and 5 deletions
  1. 14 1
      src/lib/util/csv_file.cc
  2. 9 4
      src/lib/util/csv_file.h
  3. 24 0
      src/lib/util/tests/csv_file_unittest.cc

+ 14 - 1
src/lib/util/csv_file.cc

@@ -261,7 +261,7 @@ CSVFile::next(CSVRow& row, const bool skip_validation) {
 }
 
 void
-CSVFile::open() {
+CSVFile::open(const bool seek_to_end) {
     // If file doesn't exist or is empty, we have to create our own file.
     if (size() == static_cast<std::streampos>(0)) {
         recreate();
@@ -308,6 +308,19 @@ CSVFile::open() {
                     addColumnInternal(header.readAt(i));
                 }
             }
+
+            // If caller requested that the pointer is set at the end of file,
+            // move both read and write pointer.
+            if (seek_to_end) {
+                fs_->seekp(0, std::ios_base::end);
+                fs_->seekg(0, std::ios_base::end);
+                if (!fs_->good()) {
+                    isc_throw(CSVFileError, "unable to move to the end of"
+                              " CSV file '" << filename_ << "'");
+                }
+                fs_->clear();
+            }
+
         } catch (const std::exception& ex) {
             close();
             throw;

+ 9 - 4
src/lib/util/csv_file.h

@@ -385,12 +385,17 @@ public:
     /// greater than 0. If the file doesn't exist or has size of 0, the
     /// file is recreated. If the existing file has been opened, the header
     /// is parsed and column names are initialized in the @c CSVFile object.
-    /// The data pointer in the file is set to the beginning of the first
-    /// row. In order to retrieve the row contents the @c next function should
-    /// be called.
+    /// By default, the data pointer in the file is set to the beginning of
+    /// the first row. In order to retrieve the row contents the @c next
+    /// function should be called. If a @c seek_to_end parameter is set to
+    /// true, the file will be opened and the interal pointer will be set
+    /// to the end of file.
+    ///
+    /// @param seek_to_end A boolean value which indicates if the intput and
+    /// output file pointer should be set at the end of file.
     ///
     /// @throw CSVFileError when IO operation fails.
-    void open();
+    void open(const bool seek_to_end = false);
 
     /// @brief Creates a new CSV file.
     ///

+ 24 - 0
src/lib/util/tests/csv_file_unittest.cc

@@ -303,6 +303,30 @@ TEST_F(CSVFileTest, openReadAllWrite) {
     // Any attempt to read from the file or write to it should now fail.
     EXPECT_FALSE(csv->next(row));
     EXPECT_THROW(csv->append(row_write), CSVFileError);
+
+    CSVRow row_write2(3);
+    row_write2.writeAt(0, "bird");
+    row_write2.writeAt(1, 3);
+    row_write2.writeAt(2, "purple");
+
+    // Reopen the file, seek to the end of file so as we can append
+    // some more data.
+    ASSERT_NO_THROW(csv->open(true));
+    // The file pointer should be at the end of file, so an attempt
+    //  to read should result in an empty row.
+    ASSERT_TRUE(csv->next(row));
+    EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+    // We should be able to append new data.
+    ASSERT_NO_THROW(csv->append(row_write2));
+    ASSERT_NO_THROW(csv->flush());
+    csv->close();
+    // Check that new data has been appended.
+    EXPECT_EQ("animal,age,color\n"
+              "cat,10,white\n"
+              "lion,15,yellow\n"
+              "dog,2,blue\n"
+              "bird,3,purple\n",
+              readFile());
 }
 
 // This test checks that contents may be appended to a file which hasn't