package com.viniciusfortuna.transit.gtfs; import au.com.bytecode.opencsv.CSVReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** * Class to read a GTFS specification file and return the data in a structured format. * Original Version by Vinicius Fortuna * * @author Sebastian Müller */ public class GtfsReader { public static GtfsSpec readGtfsFile(InputStream gtfsFile) throws NumberFormatException, MalformedURLException, IOException { ZipInputStream zip = new ZipInputStream(gtfsFile); ArrayList<Agency> agencies = new ArrayList<Agency>(); ArrayList<Route> routes = new ArrayList<Route>(); ArrayList<Stop> stops = new ArrayList<Stop>(); for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) { if (entry.isDirectory()) { continue; } String filename = entry.getName(); if (filename.endsWith("agency.txt")) { List<Map<String, String>> lines = readCsv(zip); for (Map<String, String> line : lines) { agencies.add(new Agency(line.get("agency_id"), line.get("agency_name"), new URL(line.get("agency_url")), TimeZone.getTimeZone(line.get("agency_timezone")))); } } else if (filename.endsWith("stops.txt")) { List<Map<String, String>> lines = readCsv(zip); for (Map<String, String> line : lines) { stops.add(new Stop(line.get("stop_id"), line.get("stop_name"), Double.parseDouble(line.get("stop_lat")), Double.parseDouble(line.get("stop_lon")))); } } else if (filename.endsWith("routes.txt")) { List<Map<String, String>> lines = readCsv(zip); for (Map<String, String> line : lines) { routes.add(new Route(line.get("route_id"), line.get("route_short_name"), line.get("route_long_name"), Integer.parseInt(line.get("route_type")))); } } } return new GtfsSpec(agencies, stops, routes); } /** * Helper method to read a CSV file and return the content as a list of maps. * @param csv the input CSV file content. * @return a list of maps, where each list element corresponds to a row in the CSV file. The map * keys are the column names from the first line of the CSV file. * @throws IOException in case of failing to read the input stream. */ private static List<Map<String, String>> readCsv(InputStream csv) throws IOException { CSVReader reader = new CSVReader(new InputStreamReader(csv)); ArrayList<Map<String, String>> lines = new ArrayList<Map<String,String>>(); String[] columnNames = reader.readNext(); if (columnNames == null) { return lines; } String[] line; while((line = reader.readNext()) != null) { HashMap<String, String> map = new HashMap<String, String>(); for (int ci = 0; ci < line.length; ++ci) { map.put(columnNames[ci], line[ci]); } lines.add(map); } return lines; } // For testing the code. public static void main(String[] args) throws NumberFormatException, MalformedURLException, IOException { System.out.println("Reading GTFS file at " + args[0]); GtfsSpec gtfs = GtfsReader.readGtfsFile(new FileInputStream(args[0])); System.out.printf("Agencies: %d\n", gtfs.agencies.size()); for (Agency a : gtfs.agencies) { System.out.printf(" Agency(%s, %s, %s, %s)\n", a.id, a.name, a.url, a.timezone); } System.out.printf("Stops: %d\n", gtfs.stops.size()); for (Stop s : gtfs.stops) { System.out.printf(" Stop(%s, %s, %f, %f)\n", s.id, s.name, s.latitude, s.longitude); } System.out.printf("Routes: %d\n", gtfs.routes.size()); for (Route r : gtfs.routes) { System.out.printf(" Route(%s, %s, %s, %d)\n", r.id, r.shortName, r.longName, r.type); } } // Not used. private GtfsReader() {} }