1   package fi.jyu.mit.ohj2;
2   import java.io.*;
3   import java.util.Scanner;
4   
5   /**
6    * Aliohjelma kahden tekstitiedoston vertaamiseksi.
7    * Käyttö lähinnä JUnit testeissä esim. seuraavasti:
8    * <pre>
9    *     VertaaTiedosto.kirjoitaTiedosto("hiljaa.txt", 
10   *         "33 hiljaa 1 hiipii\n"+
11   *         "hyvä 33 tulee\n"+
12   *         "36 1 3 5 55\n"+
13   *         "nyt 33 riittää\n");    
14   *     VertaaTiedosto.kirjoitaTiedosto("hiljaayli30.txt", 
15   *         "33 hiljaa 1 hiipii\n"+
16   *         "36 1 3 5 55\n");
17   *     VertaaTiedosto.tuhoaTiedosto("tulos.txt");
18   *     TulYli30.main(new String[]{"hiljaa.txt","tulos.txt"});
19   *     String virhe=VertaaTiedosto.vertaa("tulos.txt","hiljaayli30.txt");
20   *     if ( virhe != null ) fail(virhe);
21   * </pre>
22   * @author vesal
23   * @version 10.3.2007
24   */
25  public class VertaaTiedosto { // NOPMD Cyclomatic
26    /**
27     * Verrataan kahta tekstitiedostoa ja heti kun tulee ensimmäin poikkeava 
28     * rivi palautetaanvirhe.  Lopussa olevat pelkkä yksi rivi ei tee eroa.
29     * @param nimi1 1. verrattavan tiedoston nimi
30     * @param nimi2 2. verrattavan tiedoston nimi
31     * @return ensimmäinen eroavaisuus joka löytyy. Null jos ei eroja.
32     * @throws IOException jos lukemisessa tapahtuu virhe.
33     * @example
34     * <pre name="test">
35     * #THROWS IOException
36     * #import java.io.*;
37     * #STATICIMPORT
38     *     kirjoitaTiedosto("hiljaa1.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n");
39     *         
40     *     kirjoitaTiedosto("hiljaa2.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n"); 
41     *     vertaaFileFile("hiljaa1.txt","hiljaa2.txt") === null;
42     *
43     *     kirjoitaTiedosto("hiljaa2.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee"); 
44     *     vertaaFileFile("hiljaa1.txt","hiljaa2.txt") === null;
45     *
46     *     kirjoitaTiedosto("hiljaa2.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n\n\n");
47     *     vertaaFileFile("hiljaa1.txt","hiljaa2.txt") === "Rivi 3: hiljaa1.txt loppui ensin, hiljaa2.txt on ";
48     *
49     *     kirjoitaTiedosto("hiljaa2.txt", "33 hiljaa 1 hiipii\nhyvä 34 tulee\n");
50     *     vertaaFileFile("hiljaa1.txt","hiljaa2.txt") === "Ero riveissä 2: hyvä 33 tulee ja hyvä 34 tulee";
51     *     
52     *     kirjoitaTiedosto("hiljaa2.txt", "33 hiljaa 1 hiipii\n");
53     *     vertaaFileFile("hiljaa1.txt","hiljaa2.txt") === "Rivi 2: hiljaa2.txt loppui ensin, hiljaa1.txt on hyvä 33 tulee";
54     *
55     *     kirjoitaTiedosto("hiljaa2.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\nja 34 tulee\n");
56     *     vertaaFileFile("hiljaa1.txt","hiljaa2.txt") === "Rivi 3: hiljaa1.txt loppui ensin, hiljaa2.txt on ja 34 tulee";
57     *     vertaaFileFile("hiljaa1.txt","hiljaa3.txt") === "Tiedosto ei aukea: hiljaa3.txt";
58     *     vertaaFileFile("hiljaa4.txt","hiljaa2.txt") === "Tiedosto ei aukea: hiljaa4.txt";
59     *     
60     *     tuhoaTiedosto("hiljaa1.txt");
61     *     tuhoaTiedosto("hiljaa2.txt");
62     * 
63     * </pre>
64     */
65    public static String vertaaFileFile(String nimi1, String nimi2) throws IOException { // NOPMD
66      BufferedReader f1 = null;
67      BufferedReader f2 = null;
68      try {
69        f1 = Tiedosto.avaa_lukemista_varten(nimi1);
70        f2 = Tiedosto.avaa_lukemista_varten(nimi2);
71        if ( f1 == null ) return "Tiedosto ei aukea: " + nimi1;
72        if ( f2 == null ) return "Tiedosto ei aukea: " + nimi2;
73        int n = 1;
74  
75        while (true) {
76          String s1 = f1.readLine();
77          String s2 = f2.readLine();
78          if (s1 == null && s2 == null ) return null;
79          if (s1 != null && s2 == null ) return "Rivi "+ n + ": " + nimi2 + " loppui ensin, " + nimi1 + " on "+ s1; // NOPMD
80          if (s1 == null && s2 != null)  return "Rivi "+ n + ": " + nimi1 + " loppui ensin, " + nimi2 + " on "+ s2; // NOPMD
81          if ( s1.compareTo(s2) != 0 )   return "Ero riveissä " + n + ": " + s1 + " ja " + s2; // NOPMD
82          n++;
83        }
84      } finally {
85        if (f1 != null)
86          f1.close();
87        if (f2 != null)
88          f2.close();
89      }
90    }
91  
92    /**
93     * Verrataan tekstitiedostoa merkkijonoon ja heti kun tulee ensimmäinen poikkeava 
94     * rivi palautetaan virhe.  Lopussa olevat pelkkä yksi tyhkä rivi eo tee eroa.
95     * @param nimi1 1. verrattavan tiedoston nimi
96     * @param ss2 2. verrattava sisältö
97     * @return ensimmäinen eroavaisuus joka löytyy. Null jos ei eroja.
98     * @throws IOException jos lukemisessa tapahtuu virhe.
99     * <pre name="test">
100    * #THROWS IOException
101    * #import java.io.*;
102    * #STATICIMPORT
103    *     kirjoitaTiedosto("hiljaa1.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n");
104    *         
105    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\nhyvä 33 tulee\n") === null;
106    *
107    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\nhyvä 33 tulee") === null;
108    *
109    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\nhyvä 33 tulee\n\n") === "Rivi 3: hiljaa1.txt loppui ensin, jono on ";
110    *
111    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\nhyvä 33 tulee\n\n\n") === "Rivi 3: hiljaa1.txt loppui ensin, jono on ";
112    *
113    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\nhyvä 34 tulee\n") === "Ero riveissä 2: hyvä 33 tulee ja hyvä 34 tulee";
114    *     
115    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\n") === "Rivi 2: Jono loppui ensin, hiljaa1.txt on hyvä 33 tulee";
116    *
117    *     vertaaFileString("hiljaa1.txt","33 hiljaa 1 hiipii\nhyvä 33 tulee\nja 34 tulee\n") === "Rivi 3: hiljaa1.txt loppui ensin, jono on ja 34 tulee";
118    *     vertaaFileString("hiljaa1.txt",null) === "Jono on null"; 
119    *     vertaaFileString("hiljaa4.txt","hiljaa2.txt") === "Tiedosto ei aukea: hiljaa4.txt";
120    *     
121    *     tuhoaTiedosto("hiljaa1.txt");
122    * 
123    * </pre>
124    */
125   public static String vertaaFileString(String nimi1, String ss2) throws IOException { // NOPMD
126     if ( ss2 == null ) return "Jono on null";
127     BufferedReader f1 = null;
128     Scanner f2 = new Scanner(ss2);
129     int n = 1;
130     try {
131       f1 = Tiedosto.avaa_lukemista_varten(nimi1);
132       if ( f1 == null ) return "Tiedosto ei aukea: " + nimi1;
133       
134       while (true) {
135         String s1 = f1.readLine();
136         boolean b2 = f2.hasNextLine();
137         String s2 = null;
138         if ( b2 ) s2 = f2.nextLine();
139         if (s1 == null && !b2)         return null;
140         if (s1 != null && !b2 )        return "Rivi "+ n + ": " + "Jono loppui ensin, " + nimi1 + " on "+ s1;
141         if (s1 == null &&  b2)         return "Rivi "+ n + ": " + nimi1 + " loppui ensin, "  + "jono on "+ s2;
142         if ( s1.compareTo(s2) != 0 )   return "Ero riveissä " + n + ": " + s1 + " ja " + s2;
143         n++;
144       }
145     } finally {
146       if (f1 != null)
147         f1.close();
148     }
149   }
150 
151   /**
152    * Verrataan kahta tekstitiedoston kaltaista merkkijonoa ja heti kun tulee ensimmäinen poikkeava 
153    * rivi palautetaan virhe.  Lopussa oleva yksi tyhjä rivi ei tee eroa.
154    * @param ss1 1. verrattava sisältö
155    * @param ss2 2. verrattava sisältö
156    * @return ensimmäinen eroavaisuus joka löytyy. Null jos ei eroja.
157    * <pre name="test">
158    * #THROWS IOException
159    * #import java.io.*;
160    * #STATICIMPORT
161    *     vertaaString2("","\n") === "Rivi 1: 1. loppui ensin, 2. on ";
162    *     vertaaString2("kissa\n","kissa") === null;
163    *     vertaaString2("\n\n","\n") === "Rivi 2: 2. loppui ensin, 1. on ";
164    *     vertaaString2("\r\n","\n") === null;
165    *     vertaaString2("\r\n","\n\n") === "Rivi 2: 1. loppui ensin, 2. on ";
166    *     vertaaString2("33 hiljaa 1 hiipii\r\nhyvä 33 tulee\r\n","33 hiljaa 1 hiipii\nhyvä 33 tulee\n") === null;
167    *     vertaaString2("a b","a c") === "Ero riveissä 1: a b ja a c"
168    *     vertaaString2(null,null) === null;
169    *     vertaaString2(null," ") === "1. on null";
170    *     vertaaString2(" ",null) === "2. on null";
171    * </pre>
172    */
173   public static String vertaaString2(String ss1, String ss2)  { // NOPMD
174     if ( ss1 == null & ss2 == null ) return null;
175     if ( ss1 == null ) return "1. on null";
176     if ( ss2 == null ) return "2. on null";
177     Scanner f1 = new Scanner(ss1);
178     Scanner f2 = new Scanner(ss2);
179     int n = 1;
180     while (true) {
181       String s1 = null;
182       String s2 = null;
183       boolean b1 = f1.hasNextLine(); 
184       boolean b2 = f2.hasNextLine(); 
185       if ( b1 ) s1 = f1.nextLine();
186       if ( b2 ) s2 = f2.nextLine();
187       if ( !b1 && !b2)             return null;
188       if (  b1 && !b2 )            return "Rivi "+ n + ": " + "2. loppui ensin, 1. on "+ s1;
189       if ( !b1 &&  b2)             return "Rivi "+ n + ": " + "1. loppui ensin, 2. on "+ s2;
190       if ( s1.compareTo(s2) != 0 ) return "Ero riveissä " + n + ": " + s1 + " ja " + s2;
191       n++;
192     }
193   }
194 
195   /**
196    * Verrataan kahta tekstitiedoston kaltaista merkkijonoa ja heti kun tulee ensimmäinen poikkeava 
197    * rivi palautetaan virhe.  Lopussa olevat pelkät tyhjät rivit merkitsevät.
198    * @param ss1 1. verrattava sisältö
199    * @param ss2 2. verrattava sisältö
200    * @return ensimmäinen eroavaisuus joka löytyy. Null jos ei eroja.
201    * <pre name="test">
202    * #THROWS IOException
203    * #import java.io.*;
204    * #STATICIMPORT
205    *     vertaaString("kissa\n","kissa") === "Rivi 2: 2. loppui ensin, 1. on ";
206    *     vertaaString("","\n") === "Rivi 1: 1. loppui ensin, 2. on ";
207    *     vertaaString("\n\n","\n") === "Rivi 3: 2. loppui ensin, 1. on ";
208    *     vertaaString("\r\n","\n") === null;
209    *     vertaaString("\r","\n")   === null;
210    *     vertaaString("\r\n","\n\n") === "Rivi 3: 1. loppui ensin, 2. on ";
211    *     vertaaString("33 hiljaa 1 hiipii\r\nhyvä 33 tulee\r\n","33 hiljaa 1 hiipii\nhyvä 33 tulee\n") === null;
212    *     vertaaString("a b","a c") === "Ero riveissä 1: a b ja a c"
213    *     vertaaString(null,null) === null;
214    *     vertaaString(null," ") === "1. on null";
215    *     vertaaString(" ",null) === "2. on null";
216    * </pre>
217    */
218   public static String vertaaString(String ss1, String ss2)  { // NOPMD
219     if ( ss1 == null & ss2 == null ) return null;
220     if ( ss1 == null ) return "1. on null";
221     if ( ss2 == null ) return "2. on null";
222     ss1 = ss1.replaceAll("\\r\\n", "\n");
223     ss2 = ss2.replaceAll("\\r\\n", "\n");
224     ss1 = ss1.replaceAll("\\r", "\n");
225     ss2 = ss2.replaceAll("\\r", "\n");  // Toki nyt voitaisiin verrata pelkkiä jonoja sellaisenaan
226     Erottelija f1 = new Erottelija(ss1,"\n");
227     Erottelija f2 = new Erottelija(ss2,"\n");
228     int n = 1;
229     while (true) {
230       String s1 = null;
231       String s2 = null;
232       boolean b1 = f1.hasMoreTokens(); 
233       boolean b2 = f2.hasMoreTokens(); 
234       if ( b1 ) s1 = f1.nextToken();
235       if ( b2 ) s2 = f2.nextToken();
236       if ( !b1 && !b2)             return null;
237       if (  b1 && !b2 )            return "Rivi "+ n + ": " + "2. loppui ensin, 1. on "+ s1;
238       if ( !b1 &&  b2)             return "Rivi "+ n + ": " + "1. loppui ensin, 2. on "+ s2;
239       if ( s1.compareTo(s2) != 0 ) return "Ero riveissä " + n + ": " + s1 + " ja " + s2;
240       n++;
241     }
242   }
243 
244   /**
245    * Kirjoitetaan tiedostoon sisältö
246    * @param nimi tiedoston nimi johon kirjoitetaan
247    * @param sisalto merkkijono joka kirjoitetaan tiedostoon
248    * @throws IOException jos tiedosto ei aukea.
249    * @example
250    * <pre name="test">
251    * #THROWS IOException
252    *     kirjoitaTiedosto("hiljaa1.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n");
253    *     tuhoaTiedosto("hiljaa1.txt");
254    *     kirjoitaTiedosto("ö:\\ö.ö", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n"); #THROWS IOException
255    * </pre>
256    */
257   public static void kirjoitaTiedosto(String nimi, String sisalto) throws IOException {
258     PrintWriter out = null;
259     try {
260       out = new PrintWriter(new FileWriter(nimi));
261       out.write(sisalto);
262       out.close();
263     } finally {
264       if (out != null)
265         out.close();
266     }
267   }
268 
269   /**
270    * Tuhotaan tiedosto levyltä
271    * @param nimi tuhottavan tiedoston nimi
272    */
273   public static void tuhoaTiedosto(String nimi) {
274     File f = new File(nimi);
275     f.delete();
276   }
277 
278   /**
279    * Testataan tiedostojen vertaamista
280    * @param args ei käytössä
281    * @throws IOException jos tulee virhe
282    */
283 /*  
284   public static void main(String[] args) throws IOException  {
285     String koe = vertaaFileFile("fi/jyu/mit/ohj2/IO.java","fi/jyu/mit/ohj2/Syotto.java");
286     System.out.println(koe);
287   }
288 */
289 }
290