"50331648","67108863","ARIN","572572800","US","USA","UNITED STATES"
I use MySQL. Therefore my interest was to convert the file to a tab separated list of rows. Perl will be very good for this, but I don't know Perl. Therefore I wrote a small Java class that is used from the command line to do this. Here is the code:
/** * Changes the IpToCountry.csv file as downloaded * (after taking away the portions following the # and any empty lines) * from http://software77.net/cgi-bin/ip-country/geo-ip.pl * to a tab separated file usable by MySQL */ import java.io.*; import java.util.StringTokenizer; public class FileChanger{ private StringBuffer buffer; public FileChanger(String inputFile, String outputFile){ buffer = new StringBuffer(); go(inputFile, outputFile); } private void go(String inputFile, String outputFile){ try{ FileReader fileReader = new FileReader(inputFile); BufferedReader reader = new BufferedReader(fileReader); if(reader.ready()){ String read = reader.readLine(); while(read != null){ StringTokenizer tokens = new StringTokenizer(read, ",", false); String from = tokens.nextToken(); String to = tokens.nextToken(); // A few entries we are not interested in before we get to // the real country code String countryCode = tokens.nextToken(); countryCode = tokens.nextToken(); countryCode = tokens.nextToken(); // Replace any occurences of UK with GB if(countryCode.equalsIgnoreCase("\"UK\"")) countryCode = "GB"; String line = from + "\t" + to + "\t" + countryCode + "\n"; // Remove all quotes line = line.replaceAll("\"", ""); buffer = buffer.append(line); read = reader.readLine(); } fileReader.close(); reader.close(); PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile))); out.write(buffer.toString()); out.flush(); out.close(); } } catch(Exception e){ System.out.println("Exception: " + e.getMessage()); } } public static void main(String[] args){ if(args.length != 2){ System.out.println("Usage: java FileChanger inputFile outputFile"); System.exit(1); } FileChanger fileChanger = new FileChanger(args[0], args[1]); } }
You will notice that all occurences of UK are replaced with GB. That is not necessary if you do not want to do it.
The lines of the file created by FileChanger look like this:
50331648 67108863 US 67108864 83886079 US 100663296 117440511 US 117440512 134217727 USYou can of course adapt FileChanger to do what you want it to do.
mysql -u yourUserName yourDatabaseName -pYou will be prompted for your password and connected to your database. Now do the following:
load data local infile "ipData.txt" into table ip2country_tbl;About half a second after hitting enter all nearly 65000 rows will be loaded, DV.
String ipAddress = null; if (request.getHeader("X-Forwarded-For") == null) ipAddress = request.getRemoteAddr(); else ipAddress = request.getHeader("X-Forwarded-For"); String countryCode = codeBean.getCountryCode(ipAddress);
The host I am with uses a proxy and I get an IP Address returned in the following format:
169.23.123.89, 127.0.0.46Obviously, I am only interested in the 169.23.123.89 part. The code that will soon follow tests for a comma and then chops off everything from the comma onwards, including the comma. codeBean really only passes the String IP Address to a Stateless Session Bean, gets the returned value from the Stateless Session Bean and passes that to the JSP. Here is how the Stateless Session Bean converts the String IP Address to a java.lang.Long as stored in the database and queries the database using this Long. I'm including a the XDoclet tags in case anybody is interested.
/** * * @param IPAddress * @return a String the country code * * @ejb.interface-method * view-type="remote" * **/ public String getCountryCode(String IPAddress){ logman.debug("The IP Address passed in is " + IPAddress); // Chop off everything from the comma onwards StringBuffer buffer = new StringBuffer(IPAddress); int index = buffer.indexOf(","); // See if there is comma if(index > 0){ int length = buffer.length(); buffer = buffer.delete(index, length); } StringTokenizer tokens = new StringTokenizer(buffer.toString(), ".", false); long answer = 0L; int counter = 3; while(tokens.hasMoreTokens() && counter >= 0){ long read = new Long(tokens.nextToken()).longValue(); long calculated = new Double(read *(Math.pow(256, counter))).longValue(); answer += calculated; counter --; logman.debug("Iteratrions read backward - 3,2,1 no: " + (counter +1)); } Long IPValue = new Long(answer); logman.debug("The IP Address value is: " + IPValue.toString()); try { IP2CountryCMPLocalHome ip2countryLocalHome = IP2CountryCMPUtil.getLocalHome(); return ip2countryLocalHome.getCountryCode(IPValue); } catch (NamingException e) { logman.error(e.getMessage()); return "GB"; } }
You will notice some Log4J debugging code. I leave it and just change the log level. Very handy. The bit in the try clause is where the database is queried and the result returned. In actual fact the IP2CountryCMPBean (container managed persistence bean) is cached in memory and the database won't be accessed until the values in this table change again. You will know how this speeds things up.
IP to Country Mapping seems to be ideal for a Web Service. As you can see, it will not be difficult to do either.
Well, that's all folks.