Store and read multi-dimensional array data by row based on the ini configuration file

Source: Internet
Author: User

The requirement is to store the data of a multi-dimensional array object to a file by row. The key-value pairs need to be differentiated and the description of each object is clear. The format is as follows:


The data in corresponds to the following array (PHP language ):

$arr = array(           '10003' => array(                              'id' => 10003,                              'tokentime' => 400),                    '10005' => array(                              'id' => 10005,<p>                               'cookie' => array(</p>                                                 'num' => 20                                                 ),                                'vcode' => array(                                                'length' => 6                                                 ),                                ),);
Each ID corresponds to a data object, but this data object may be multi-dimensional data and needs to be stored in a file that is user-friendly, here it is easy to think that the JSON format is also acceptable. After the json_encode array is stored in the file, the json_decode can be used to parse it into an array or an object during reading. This is indeed a convenient method, but this case uses the row-based storage format. Therefore, you need to implement the parsing and storage process on your own.

Through the analysis of the above format, we can easily think of the INI file format. Brackets distinguish blocks and the following correspond to key-value pairs, however, here is a note that dianhao (". ") represents the hierarchical relationship of the block. The formal hierarchical relationship shows the multi-dimensional and readability of the array, which is also a very clever way.

However, when the parse_ini_file function of PHP reads an INI file, if the block name is the same, the new block content will overwrite the previous block. The official PHP manual is described as follows:

Array parse_ini_file (string $ filename [, bool $ process_sections = false [, int $ scanner_mode = ini_scanner_normal]) parse_ini_file () loads an INI file specified by filename, and return the settings as a Union array. The structure of the INI file is similar to that of PHP. ini. The name of the INI file to be parsed by the filename parameter. Process_sections if the last process_sections parameter is set to true, a multidimensional array is obtained, including the name and settings of each section in the configuration file. The default value of process_sections is false. Scanner_modecan either be ini_scanner_normal (default) or ini_scanner_raw. If ini_scanner_raw is supplied, then option values will not be parsed.

That is [. 10003 [.. cookie] block. After reading the file ,[. 10005 [.. cookie] The block will overwrite the content of the former. Of course, you can choose not to use the parse_ini_file function, but to read the file by row. Here, I still use the parse_ini_file function. Because the above file format is an extension of the standard INI file format, it is more convenient to directly use it to return an array immediately and then process the array.

Implementation Policy: The parse_ini_file function is used, but the block policy uses the parent key name + its own key name to avoid duplication.

The write method is as follows:

     public function setAppInfo($app, $path){         $appStr = "[app]\n";         $ret = '';         self::readArrayRecursive(array_reverse($app, true), $ret, 'app', 1);         return file_put_contents($path, $ret);     }      //setAppInfo helper     private function readArrayRecursive($arr, &$str = '', $prefix,  $level = 1){         foreach($arr as $k => $v){             if (is_array($v)){                 $str .= "[" . str_repeat('.', $level) . $prefix . ':'  . $k . "]\n";                 $level++;                 self::readArrayRecursive($v, &$str, $k, $level);                 $level--;             }else{                 $str .= "$k=$v\n";             }         }     }
The essence of this implementation is to piece together an existing multi-dimensional array to produce a string with clear multi-dimensional array hierarchies, and finally write it into the specified file.

When a recursive auxiliary function is called in the main call function, the recursion method looks simple, but is not easy to write, especially the level parameter and the final string STR parameter passed each time, these two parameters are very important. First, the string is null, And the prefix specifies the initial prefix. The level is 1. The array elements are traversed, and each element determines whether it is an array. If it is not an array, the string is directly pieced together, if it is an array, the block name is used. After level is increased by 1, the array is recursive. After the array is completed, level 1 is reduced and 1 is returned to the current level.

The read method uses the parse_ini_file function to read and adjust the array. The adjustment method can also be implemented using recursion. However, since recursive is used for writing, I used the stack to simulate recursive calls to implement non-recursive writing methods:

Public Function getappinfo ($ PATH) {// read $ appinfo = parse_ini_file ($ path, true) by section; // perform simultaneous merging $ kstack = array (); // use the stack to process the level key $ level = 0; // the level of the top element of the stack $ clevel = 0; // The array_push ($ kstack, 'app'); foreach ($ appinfo as $ k = >$ v) {If ('app' = $ K) {continue ;} elseif (empty ($ appinfo [$ K]) {// clear unset ($ appinfo [$ K]); continue;} $ clevel = self :: getlevel ($ K); if ($ clevel> $ level) {array_pu Sh ($ kstack, $ K); $ level = $ clevel;} else {$ levelkeys = array (); // save key names that are deeper than the current Element Level $ KL = $ level; do {$ KK = array_pop ($ kstack); $ levelkeys [] = $ KK; $ KL = self: getlevel ($ KK);} while ($ KL! = $ Clevel); // obtain all key names deeper than the current element level. The last key is the same as the current element $ upkey = array_pop ($ levelkeys ); foreach ($ levelkeys as $ downkey) {$ realk = explode (":", $ downkey); $ appinfo [$ upkey] [$ realk [count ($ realk) -1] = $ appinfo [$ downkey]; unset ($ appinfo [$ downkey]);} // press the array_push ($ kstack, $ upkey, $ K) of the same level as the last retrieved element; $ level = $ KL ;}} while (count ($ kstack)> 1) {$ KK = array_pop ($ kstack); $ level = self: getlevel ($ KK ); $ kkarr = array ($ KK); $ kkup = array_pop ($ kstack); $ kkupl = self: getlevel ($ kkup); While ($ kkupl = $ level) {$ kkarr [] = $ Kup; $ kkup = array_pop ($ kstack); $ kkupl = self: getlevel ($ kkup);} foreach ($ kkarr as $ down) {$ realk = explode (':', $ down); $ appinfo [$ kkup] [$ realk [count ($ realk) -1] = $ appinfo [$ down]; unset ($ appinfo [$ down]);} array_push ($ kstack, $ kkup );} return $ appinfo ['app'];} // getappinfo helper private function getlevel ($ key) {$ level = 0; while ('. '= substr ($ key, 0, 1) {$ level ++; $ key = substr ($ key, 1);} return $ level ;}
The main strategy is to use the kstack stack to store the key names of elements greater than or equal to the level of the current traversal element under the current block. After the final traversal is complete, the stack is cleaned up, return the final cleared array.

The above implementation is just a policy. As I mentioned earlier, you can consider using the JSON or XML format, or you can use the INI format to read data by row without using the parse_ini_file function, therefore, there are various implementation methods, and this method is not fixed in this article. I would like to record and share it here.





Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.