001package fi.jyu.mit.ohj2; 002 003import java.io.BufferedReader; 004import java.io.File; 005import java.io.FileNotFoundException; 006import java.io.FileReader; 007import java.io.FileWriter; 008import java.io.IOException; 009import java.io.PrintWriter; 010import java.util.Map; 011import java.util.TreeMap; 012 013 014/** 015 * Luokka ini-tiedoston käsittelyyn. Tiedoston muoto: 016 * <pre> 017 * [FormGUI] 018 * leveys=200 019 * korkeus=100 020 * cbEtsi=1 021 * [Positions] 022 * FormGUI=0,0 023 * </pre> 024 * 025 * Usea ohjelman osa voi "luoda" tiedoston uudestaan, koska jo avattut 026 * tiedostot puskuroidaan, eikä niitä avata enää toista kertaa. 027 * Tämä ei kuitenkaan ole vielä thread-safe. 028 * 029 * @author vesal 030 * @version 14.6.2013 031 * 032 * @example 033 * <pre name="test"> 034 * #import java.io.File; 035 * File fini = new File("testini.ini"); 036 * File fini2 = new File("testini2.ini"); 037 * fini.delete(); fini2.delete(); 038 * 039 * IniFile ini = IniFile.create("testini.ini"); 040 * ini.write("FormGUI","leveys",200); 041 * ini.write("FormGUI","korkeus",100); 042 * ini.write("FormGUI","cbEtsi",1); 043 * ini.write("Positions","FormGUI","20,30"); 044 * 045 * fini.renameTo(fini2) === true; // koska saman luominen ei loisi mitään uutta 046 * 047 * ini = IniFile.create("testini2.ini"); 048 * ini.read("FormGUI","leveys",0) === 200; 049 * ini.read("FormGUI","korkeus",0) === 100; 050 * ini.read("FormGUI","cbEtsi",0) === 1; 051 * ini.read("FormGUI","cbEiOo",2) === 2; 052 * ini.read("eioo","cbEiOo",2) === 2; 053 * ini.read("Positions","FormGUI","1,1") === "20,30"; 054 * ini.write("FormGUI","cbEtsi",0); 055 * ini.read("FormGUI","cbEtsi",9) === 0; 056 * fini2.delete() === true; 057 * </pre> 058 * 059 */ 060public class IniFile { 061 062 private static TreeMap<String,IniFile> iniFiles = new TreeMap<>(); 063 064 /** 065 * Luodaan uusi ini-file tai annetaan entinen jos on jo kerran luettu 066 * @param fileName minkä nimistä tiedostoa käsitellään 067 * @return luota tai puskurista otettu tiedosto 068 */ 069 public static IniFile create(String fileName) { 070 File file = new File(fileName); 071 String fullname = file.getAbsolutePath(); 072 IniFile result = iniFiles.get(fullname); 073 if ( result != null ) return result; 074 result = new IniFile(fullname); 075 iniFiles.put(fullname, result); 076 return result; 077 } 078 079 private String fileName; 080 private TreeMap<String,TreeMap<String,String>> sections = new TreeMap<>(); 081 082 /** 083 * @param fileName luettavan tiedoston nimi 084 */ 085 private IniFile(String fileName) { 086 this.fileName = fileName; 087 readFile(); 088 } 089 090 091 private String lastSectionName = null; 092 private TreeMap<String,String> lastSection = null; 093 094 095 private TreeMap<String, String> getSectionValue(String section) { 096 if ( section.equals(lastSectionName) ) return lastSection; 097 lastSectionName = section; 098 lastSection = sections.get(section); 099 if ( lastSection != null ) return lastSection; 100 lastSection = new TreeMap<>(); 101 sections.put(section, lastSection); 102 return lastSection; 103 } 104 105 106 private TreeMap<String, String> getSectionValueNoCreate(String section) { 107 if ( section.equals(lastSectionName) ) return lastSection; 108 TreeMap<String,String> last = sections.get(section); 109 if ( last == null ) return null; 110 lastSection = last; 111 lastSectionName = section; 112 return lastSection; 113 } 114 115 116 private void writeNoSave(String section, String item, String value) { 117 TreeMap<String,String> sectionValue = getSectionValue(section); 118 sectionValue.put(item, value.replaceAll("\n", "\\\\n")); 119 } 120 121 122 private void readFile() { 123 String sectionName = ""; 124 try ( BufferedReader fi = new BufferedReader(new FileReader(fileName)) ) { 125 String rivi; 126 while ((rivi = fi.readLine()) != null) { 127 rivi = rivi.trim(); 128 if ( rivi.startsWith("[")) { 129 sectionName = rivi.replace('[', ' ').replace(']', ' ').trim(); 130 continue; 131 } 132 int p = rivi.indexOf('='); 133 if ( p < 0 ) continue; 134 String itemName = rivi.substring(0,p); 135 String value = rivi.substring(p+1); 136 writeNoSave(sectionName, itemName, value); 137 } 138 139 } catch ( FileNotFoundException e ) { 140 // Mitäs tehtäis 141 } catch (IOException e) { 142 // Mitäs tehtäis 143 } 144 } 145 146 147 /** 148 * Tallenttaa koko rakenteen 149 */ 150 public void saveFile() { 151 File ftied = new File(fileName); 152 153 try ( PrintWriter fo = new PrintWriter(new FileWriter(ftied.getCanonicalPath())) ) { 154 for (Map.Entry<String,TreeMap<String,String>> entry : sections.entrySet()) { 155 fo.println("[" + entry.getKey() + "]"); 156 for (Map.Entry<String,String> item : entry.getValue().entrySet()) { 157 fo.println(item.getKey() + "=" + item.getValue()); 158 } 159 } 160 } catch ( FileNotFoundException ex ) { 161 // Mitäs tehtäis 162 } catch ( IOException ex ) { 163 // Mitäs tehtäis 164 } 165 166 } 167 168 169 /** 170 * Kirjoitetaan uusi arvo 171 * @param section mihin osioon kirjoitetaan 172 * @param item mikä on nimi 173 * @param value mikä on uusi arvo 174 */ 175 public void write(String section, String item, String value) { 176 writeNoSave(section, item, value); 177 saveFile(); 178 } 179 180 181 /** 182 * Kirjoitetaan uusi arvo 183 * @param section mihin osioon kirjoitetaan 184 * @param item mikä on nimi 185 * @param value mikä on uusi arvo 186 */ 187 public void write(String section, String item, int value) { 188 write(section,item,""+value); 189 } 190 191 192 /** 193 * Luetaan arvo 194 * @param section mistä osioista luetaan 195 * @param item mistä kohdasta luetaan 196 * @param defValue mikä arvo palautetaan jos itemia ei löydy 197 * @return löydetty arvo tai oletus 198 */ 199 public String read(String section, String item, String defValue) { 200 TreeMap<String,String> sectionValue = getSectionValueNoCreate(section); 201 if ( sectionValue == null ) return defValue; 202 String result = sectionValue.get(item); 203 if ( result == null ) return defValue; 204 result = result.replaceAll("\\\\n", "\n"); 205 return result; 206 } 207 208 209 /** 210 * Luetaan arvo 211 * @param section mistä osioista luetaan 212 * @param item mistä kohdasta luetaan 213 * @return löydetty arvo tai null jos ei löydy 214 */ 215 public String read(String section, String item) { 216 return read(section,item,(String)null); 217 } 218 219 220 /** 221 * Luetaan arvo 222 * @param section mistä osioista luetaan 223 * @param item mistä kohdasta luetaan 224 * @param defValue mikä arvo palautetaan jos itemia ei löydy 225 * @return löydetty arvo tai oletus 226 */ 227 public int read(String section, String item, int defValue) { 228 String result = read(section,item); 229 if ( result == null ) return defValue; 230 return Mjonot.erotaInt(result,defValue); 231 } 232 233 234}