Fiona Fiona - 6 months ago 17
Java Question

Scan text file in Java

I have a text file in US-ASCII which contains a single, long line. The text items that I need to access are separated by a varying number of spaces, like this:

metadata1 attrib1 metadata2 attrib2 attrib2a trackstart attrib1 attrib2 trackstart attrib1 atrib2 attrib3


The file can have a maximum of 99 'track' entries and will take little memory.

What I need to do

I have to extract these entries into an in-memory structure that I can iterate over, access values, and count items. For instance I need to get the number of 'tracks' (by counting the 'trackstart's in the above example, and also add the attributes for each track into a structure like
object.track1.attribute1
.

What I have tried

I used a Scanner to read in the file and step through the text entries. This seems to work fine. I then created nested HashMaps, like:

HashMap<String, String> overallMap = new HashMap<String, String>(); // contains the tracks map and some other metadata
HashMap<String, Map> tracks = new HashMap<String, Map>(); // contains a map of all tracks
HashMap<String, String> track = new HashMap<String, String>(); // contains an individual track


But the problem is that (I think) HashMaps won't let me count the keys (so I can't, say, get the number of 'tracks' in my text file). I suspect I'll run into other issues with this data structure.

Questions


  1. In this case, is a Scanner the best way to read in and manipulate the file?

  2. What in-memory data structure should I choose? How can I build up the track list, count the tracks, and access individual attributes in this structure?


Answer

Since you have some metadata objects and some tracks, where each has variable number of attributes, we could have a base class named "MyObjects" to represent each of them

public class MyObject implements java.io.Serializable
{
    String name;
    ArrayList attributes;
    public MyObject(String name)
    {
       this.name = name;
    }
    public void addAttribute(String attr)
    {
        this.attributes.add(attr);
    }
}

And then have a class MyFile which would represent each file that you read.

public class MyFile
{
    MyObject[] metadata;
    MyObject[] track;

    public int check(String s)
    {
        if(s.substring(0,s.length()-1).equals("metadata")) return 0;
        if(s.equals("trackstart")) return 1;
        return 2;
    }
}

Then in the main function you could read the file

File f = new File(filepath); 
BufferedReader br = new InputStreamReader(f.getInputStream());
String line = "",content = "";
while((line = br.readLine())!=null) content += line;

MyFile myfile = new MyFile();
StringTokenizer t = new StringTokenizer(content," ");
int status;
String word = "";
while(t.hasMoreTokens())
{
    word = t.nextToken();
    status = myfile.check(word);

    // add the attributes to the to metadata or tracks

 }
Comments