C design log: read and write delimiter file
Glory 2003
I will write a "C Design Practice" series of "C Design Practices", which will tell some data processing system design methods. I don't want the article to be limited to a specific database product, and I don't like the empty space to tell too much abstraction. I have to write some code that simulates the database operation, and the class DELIMFILE for reading and writing the delimiter file.
I didn't intend to write a "complete class". If you only write an article, a "demo class" with ten member functions is sufficient. But in the code writing process, I gradually realized that this class definitely has practical value, such as a small data acquisition system, can be stored in file mode. What's more, it is complete, which also helps me write subsequent code and corresponding articles. Since the profit is self-sufficient, why not?
Before I started, I immediately saw that there is no resource that can be used. In http://codegurbü.earthWeb.com/mfc_database/cspreadsheet.html, I found CSPReadsheet. This is a class that can be read using the MFC, which can be read, despite the limited function, but in general, it does not meet my requirements.
I don't plan to use MFC. I hope these codes, as well as subsequent series of code, can have good portability. No matter what C compiler you use, what kind of operating system is working, I hope they are useful to you. Obviously, the best expression means is standard C and STL, so there is DelimFile, but I would like to thank the CSPReadsheet author's groundbreaking work (for me).
I have to make a hierarchy for this class. Numerical operations such as MAX / Min / MEAN / SUM, providing DELIMFILE, is not the responsibility of delimfile, which is the flexible access to the file. As for how to deal with the value read, it is the user's business. For me, I will write another code to complete these common numerical calculations.
The DelimFile class you are now available now, provides approximately fifty public member functions, support all common access to the delimiter file. For example, read, INSERT, UPDATE, DELETE rows / column / data, and supports extension operations such as Sort, and perform SWAP in line / columns.
This class is designed from CSPReadsheet. First read the contents of the file into memory, all follow-up is done in memory. You can start to modify the memory data, call the commission () method, to call the COMMIT () method to modify the transfer to the disk file. If you want to give up all memory data modifications since the most recent submission, call Rollback ().
Below is the DelimFile full header file description, you can skip it. After this lengthy description, there is a simple example of a demonstration usage, as well as some text descriptions, which may be more looking at.
/ ************************************************** *************************** File Name: DELIMFILE.H * Features: It is used to read and write flat files with delimiter. Written by standard C / STL. * Servers: Glory * Published: January 11, 2003 * Sound: Any individual / organization can use this code for non-commercial purposes. * Version: beta1 * CopyRight (c) Royaloo.com by Royal. All Rights Reserved. ************************************************** ********************************************* / / / # IFNDEF _DELIMFILE_H_ # define _delimfile_h _ // # include < String> #include #include #include #include //// Note: Error information constant list, you can freely convert to the language you need .//const std :: string err_row_smaller_than_2 = "total row count is smaller than two / n"; const std :: string err_col_smaller_than_2 = "total col count is smaller than two / n"; const std :: string err_col_initial_already = "cols have been initialized already / n" ; const std :: string err_first_row_equal_second_row = ". first row no equal second row no./n";const std :: string err_first_col_equal_second_col =" first col no equal second col no./n";const std :: string err_col_out_of_range =. "col NO. o ut of range / n "; const std :: string err_row_out_of_range =" row no out of range / n. "; const std :: string err_cell_out_of_range =" cell coordinate out of range / n "; const std :: string err_row_size_too_large =" row size is larger than total cols / n "; const std :: string err_fail_to_initial_col_headers =" fail to initialize col headers / n "; const std :: string err_fail_to_write_file =" fail to write to file / n "; const std :: string Err_FAIL_TO_OPEN_FILE = "fail to open file / n"; const st: string err_fail_to_clear = "fail to clear file content / n";
const std :: string err_fail_to_append_row = "fail to append row / n"; const std :: string err_fail_to_insert_row = "fail to insert row / n"; const std :: string err_fail_to_update_row = "fail to update row / n"; const std :: string err_fail_to_delete_row = "fail to delete row / n"; const std :: string err_fail_to_read_row = "fail to read row / n"; const std :: string err_fail_to_append_col = "fail to append col / n"; const std :: string err_fail_to_insert_col = "fail to insert col / n"; const std :: string err_fail_to_update_col = "fail to update col / n"; const std :: string err_fail_to_delete_col = "fail to delete col / n"; const std :: string err_fail_to_sort_col = "Fail to Sort COL / N"; const st: string err_fail_to_update_cell = "fail to update cell / n"; //// Used: Each line string buffer size, you can freely set it as needed. / const Int row_buf_size = 3000; // Class DelimFile {public: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////> Several spaces "" or a semicolon "" (considering "human" readability). // backup: Do you need to make a backup when opening a file. Yes, the backup file is file_name ".bak" ./// DELIMFILE (Const std :: string & file_name, c Onst std :: string & separator, bool backup = true); /// / no code. // ~ delimFile (); public: /// / Role: Initialized column title. Title bar and normal ROW is not different, line Row is 1, is the title bar. //Value: The name of the title bar. Note that this method does not limit the column header name unique .//BOOL INITIAL_COL_HEADERS (const std :: vector & value); /// Role: Insert a row .//value: For the value of the entered row, all methods of writing the operation of the line will determine if the number of values // is exactly equal to the number of columns, otherwise Not allowed to write. This is to ensure that all data is rectangular ./row: Bax number. Inserted before this line .//BOOL INSERT_ROW (Const std :: Vector & value, int) ; /// Role: Update a line .//value: This value will be used to update the target row ./Row: Bax number. This is updated .//BOOL Update_row (const st :: vector &
Value, int ROW); //// Role: Delete a line ./row: Bax number. This strike will be deleted .//BOOL DELETE_ROW (int ROW); //// Role: Read a line .//Value: The read value is stored in this .//row: Line number. This line will be read .//bool read_row (std :: vector & value, int in); //// Role: At the end Additional line .//value: Value to be attached .//BOOL APPEND_ROW (const st :: vector & value); /// / effect: Update eligible row. //Value : For this value to update .//cl 列 号. The column will be determined .//condition: Conditions. ///Condition: Conditions. The first line .//BOOL Update_Rows (const st :: Vector & value, int co, std :: string condition, bool only_first = false); /// / function: Update eligible row . //Value: Do this value .//cl 列 列 Name. Conditionally determine the column. Note that the column name is not allowed to repeat // If there is repetition, it will be with the column name The first list is accurate .//condition: Condition. :: String> & Value, Std :: string col, std :: string condition, bool only_first = false); /// Role: Delete the eligible row .//col: List, will condition for the column Judgment .//condition: Conditions. //Only_first: Delete all lines that meet the conditions, otherwise, only delete the first line of eligible .//bool delete_rows (int COL, Const std :: ST Ring & Condition, Bool Only_First = FALSE); /// Role: Delete the eligible row .//col: column name, the column will be customized. Note that there is no limit to the column name is not allowed, // There is a repetition, will be subject to the first list with the column name. //Condition: Conditions. ///Condition: Conditions. //Only_first: Delete all the rules of the eligible, otherwise only the first line of eligible conditions. Bool delete_rows (const st: string & col, const st: string & condition, bool only_first = false); /// / action: Read the qualified row. //Value: Read the result stored in this variable. // col: List, the column will determine the column .///condition: Conditions .//BOOL Read_Row (std :: vector & value, int co, const st :: string & condition; /// / effect: Read the qualified row .//value: Read the result stored in this variable .//col: Column name, the column will determine the column. If some column name is repeated, With the first list with the column name, it is quasi .//condition: Condition .//BOOL Read_Row (std :: vector &
Value, Const std :: string & col, const st :: string & condition; /// / effect: Read the eligible all rows .//values: Read the result is stored in this variable .//cl l No. The column is criticized .//Condition: Conditions .//BOOL Read_Rows (std :: Vector > & value, int col, const st:: string & condition) ; /// The role: read all rows that meet the requirements .//values: Read the result is stored in this variable .//col: Column name. Conditionally determine the column. If some column name is repeated The first list with the column name will be accurate .//condition: condition .//bool read_rows (std :: Vector > & value, const st: string & col Const std :: string & condition; /// / effect: Add a column .//name: Column name. That is the column title. That is, the name of the Cell in the first line is displayed .//Value: Except for the first line All the values of all the columns, the default is a string with a space. /Bool append_col (const st: string & value, const st: string & value = "); ///_ 作 作: Insert a column. // name: Column name, the column title name, that is, the name of the Cell in the first line .//col: Location column, will insert a column before the column. //Value: Except for the first line All the values of these columns, default is a string with a space. /BOOL INSERT_COL (const st: string & name, int co, const st :: string & value = "); //// Role: Insert a column .//name: Column name, ie list title, the name of the Cell shown in the first line .//cl: column name. The column will be critically determined. If the column name is repeated, it will be The first list of the column name is quasi. //Value: In addition to all the values of the column outside of the first line, the default is a string with a space. /BOOL INSERT_C OL (Const std :: string & name, const st :: string & var, const st :: string & value = "); /// / function: update a column .//col: List. That will be updated. / Value: In addition to all the values of all the columings outside the first line, the default is "updated" .// Bool Update_col (int COL, Const std :: string & value = "updated"); /// / Role: Update a column. / col: column name. The column will be customized. If the column name is repeated, the first list with the column name will be accurate .//Value: In addition to all the values of the column outside the first line, Default "Updated" .// Bool Update_col (const st: string & var, const st: string & value = "updated"); ///_ 作: Delete a column .//col: List. Will delete the column .//Bool Delete_col (INT COL); /// Role: Delete a column .//col: Column name. The column will be judged. If the column name is repeated, it will be in the first Listed as accurate .//BOOL DELETE_COL (const std :: string & col);
//// The role: read a column, with column headings. //Value: Read the result stored here .//col: List. The list will be read .//BOOL READ_COL (std :: vector & Value, INT COL); /// Role: Read a column, with column headings. //Value: The read result is stored here .//col: Column name. Conditional judgment of the column. If there is a column name repetition, the first list with the column name is quasi .//bool read_col (std :: vector & value, const st: string & col); //// Role: Update column header. //Value: Do you want to update this value .//cl 列 号. This will be updated .//BOOL Update_col_name (const st: string & value, int co); /// Role : Update column header. .//Bool Update_col_name (const st :: string & var); /// / Role: Update Cell (Row, COL) Value. //Value: Do you want to update this value .//col : List .//row: Line No .//Bool Update_cell (const st: string & value, int col, int in); /// / Role: Update Cell (Row, COL) value .//Value: want Update in this value .//col: Column name. If the column name is repeated, the first list with the column name will be quasi ./row: Line number .//BOOL Update_cell (const std :: string & Value, Const std :: string & col, int in; /// / role: Read Cell (Row, COL) value .//Value: The read value is stored here .//col: List .//row : Line number .//BOOL READ_CELL (std :: string & value, int col, int ring); ///___Val (Row, COL) value .//value: Read value Store this .//col: column name. If the column name is repeated, the first list with the column name is quasi ./Row: Line number .//bool read_cell (std :: string & value, const Std :: string & col, int in; /// / effect: swap two columns position. / Role: Exchange two columns .//cl: column name. If the column name is repeated, the first list with the column name is quasi. Take the first list with the column name as accurate .//Bool swap_cols (const st :: string & second_col); ///__ // / Root: Switch two lines position. //First_row: Line number. // second_row: Line number .//Bool swap_rows (int first_row, int standard_row); /// Role: Sort above the column (according to alphabetical order) .// COL: List .//asc: true is ascending False is descending. The default is ascended .//BOOL SORT_COL (int COL, BOOL ASC = TRUE);
/// The effect: Sort above (in alphabetical order) .// col: column name. If the column name is repeated, the first list with the column name is quasi .//asc: true Ascending, false is descending, default is ascended .//BOOL SORT_COL (const st: string & col, bool asc = true); /// / Root: Cleach the cache, and empty the file content. / /BOOL clear (); / /// Role: Start transaction .//void begin_Transaction (); //// Role: Submit transaction. Change all memory, persistent to data files. / /BOOL COMMIT (); //// Roll to the last transaction submission point, give up all memory modifications. ///// Role: Determine if a given column number is within the valid range [1, m_col_total_count] .// col: List. // BOOL IS_COL_IN_RANGE (INT COL); /// Role: Determines if the given line number is within the effective range [1, m_row_total_count] .// Row: Line No .//BOOL IS_ROW_IN_RANGE (int Row); // // Role: Determines if a given Cell (Row, COL) is within the effective range [1, 1] [1, m_col_total_count] // [m_row_total_count, m_col_total_count]. // col: list ./ / ROW: Line number .//BOOL IS_CELL_IN_RANGE (int COL, INT ROW); //// Role: Return all column headings. //Value: Return Value stored here .//void get_col_names (std :: vector & value) const; /// / Role: By the given column name, return to the corresponding column number .//col: column name. If the column name is repeated, the first column with the column name will be For the case .//int get_col_no (const st :: string & col) const; /// / Return: Return to the total number of lines .//int get_row_total_count () const; //// Run: Return the total number of columns .//inT GET_COL_TOTAL_CONT () const; /// / Role: Returns the current line number. // int GET_CURRENT_ROW_NO () const; //// Role: Return backup status .//bool get_backup_status () const; //// Relive: Return to transaction status. / /BOOL get_TRANSACTION_STATUS () const; /// / Role: Returns the most recent error message .// -/const std :: string & get_last_error () const; protected: //// Role: Open the file, read the content to m_rows, the end of the "/ R". / /BOOL Open (); //// Role: Set the string in the vector, and return the result string .//std::String Delimit (const std :: vector & value) PRIVATE: / / / Role: File backup status .//BOOL M_BACKUP; //// Role: Transaction status ./////_ 作 作: 行 行 .///int m_current_row; // // Role: Total number of lines .//int m_row_total_count; /// Role: A total of columns .//inT m_col_total_count; /// 作 作: The file name is operated ./std::String m_file_name; // // Role: Deliners, such as several spaces / symbols / letters, etc ../std::4tring m_separator; /// Role: The most recent error message .//std::String m_last_error;
/// / effect: all column names .// std :: Vector m_col_names; /// / Root: All row values .// std :: vector m_rows;}; #ENDIF / ******************************************************** ****************************
A test example:
#include "delimfile.h" #include "utils.h" // The content of this file is briefly description of the contents of this file, and Int main () {DELIMFILE DF ("Test.dat", ""); DF. Clear (); Vector TV; String Ts; char ch = 'a'; df.begin_TransAction (); for (int i = 1; i <= 5; i) {tv.clear (); for (int J = 1; j <= 5; J) {TS = StringMaker () << (CH ) << i; tv.push_back (ts);} if (i == 1) {df.initial_col_headers TV);} else {df.append_row (TV);} ch = 'a';} df.commit (); cout << "Total Number of rows = << DF.GET_ROW_TOTAL_COUNT () << Endl; for INT i = 1; i <= df.get_row_total_count (); i) {df.read_row (TV, I); for (size_t j = 1; j <= tv.size (); J) {IF (j! = tv.size ()) { COUT << TV.at (j-1) << "/ t";} else {cout << tv.at (j-1) << "/ n";}}} cout << "Total Number of Columns = "<< DF.GET_COL_TOTAL_COUNT () << Endl; TV.clear (); DF.Read_col (TV," C1 "); for (size_t i = 1; i <= tv.size (); i) {Cout << static_cast (i) 1 << ":" <<
Tv.at (i-1) << Endl;} if (Df.Read_cell (TS, 2, 4)) {cout << "Cell Value At (2, 4):" << TS << Endl;} Else {Cout << DF.GET_LAST_ERROR () << Endl;}} Compiled in the "Command Prompt window", the operation is as follows (two C compiler have been used):
F: / DelimfileTest> cl / GX dftest.cpp delimfile.cpp Microsoft (R) 32-bit C / C Optimizing Compiler Version 13.00.9466 for 80x86 Copyright (C) Microsoft Corporation 1984-2001 All rights reserved dftest.cpp delimfile.. .CPP is generating code ... Microsoft (R) Incremental Linker Version 7.00.9466 Copyright (c) Microsoft Corporation. All rights reserved. /out:dftest.Exe dftest.obj delimfile.obj f: / delimfiletest> BCC32 DFTEST.CPP delimfile.cpp Borland C 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland dftest.cpp: delimfile.cpp: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland F: / DelimfileTest> dftest total number of rows = 5 A1 B1 C1 D1 E1 A2 B2 C2 D2 E2 A3 B3 C3 D3 E3 A4 B4 C4 D4 E4 A5 B5 D5 E5 Total Number of Column = 5 1: C1 2: C2 3: C3 4: C4 5: C5 Cell Value At 2, 4): B4
Open the Test.dat file with NOTEPAD, the content is as follows:
"A1" "B1" "C1" "D1" "E1" "A2" "C2" "D2" "A3" "B3" "C3" "D3" "E3" "A4" "B4" "C4" "D4" "E4" "A5" "B5" "C5" "D5" "E5"
As for the Utils.h file, the definition of the StringMaker class used in the above example is included in the file. This exquisite "Helper Class" is defined as follows:
Class stringmaker {public: template stringmaker & operator << (const t & t) {osm << t; return * this;} Operator std :: string () const {return osm.str ();} private: std :: OSTRINGSTREAM OSM;}; because of std :: string, the ready-made function like format, as a CSTRING (MFC) can be called, I use this class to construct a "" Std :: string string with parameters.
Although most developments in DelimiFile are completed in a text editor and command line compiler, you can of course use it in any C IDE and can be used for any graphical interface program. However, pay attention to the additional files that may be needed, such as in the Visual C project, don't forget to include the stdafx.h file.
If you work in Visual C , you should use the MFC if you plan to try DelimFile, you may need to convert between CString and std :: string. Here is one of the conversion methods:
Std :: string ts1 ("string"); cstring cs (ts.c_str ()); std :: string ts2 (cs.getstring ());
I have completed this class's code writing work, but I don't have more time and effort to test. The source code has been opened here [DelimFile.h] [DelimFile.cpp] [utils.h] (note that they are in an update), I hope to get a positive feedback, whether it is bug report or other.
Please write to me: Royal@royaloo.com
I wish you all a happy new year.
-Finish-