1

我有一个 US-ASCII 文本文件,其中包含一条长行。我需要访问的文本项由不同数量的空格分隔,如下所示:

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

该文件最多可以有 99 个“曲目”条目,并且占用的内存很少。

我需要做什么

我必须将这些条目提取到一个内存结构中,我可以对其进行迭代、访问值和计数项目。例如,我需要获取“轨道”的数量(通过计算上面示例中的“轨道开始”,并将每个轨道的属性添加到结构中,例如object.track1.attribute1.

我试过的

我使用扫描仪读取文件并逐步浏览文本条目。这似乎工作正常。然后我创建了嵌套的 HashMap,例如:

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

但问题是(我认为)HashMaps 不会让我计算键(所以我不能,比如说,在我的文本文件中获取“轨道”的数量)。我怀疑我会遇到这个数据结构的其他问题。

问题

  1. 在这种情况下,扫描仪是读取和操作文件的最佳方式吗?
  2. 我应该选择什么内存数据结构?如何建立曲目列表、计算曲目并访问此结构中的各个属性?
4

2 回答 2

0

由于您有一些元数据对象和一些轨道,其中每个都有可变数量的属性,我们可以有一个名为“MyObjects”的基类来表示它们中的每一个

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);
    }
}

然后有一个 MyFile 类,它代表您阅读的每个文件。

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;
    }
}

然后在主函数中你可以读取文件

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

 }
于 2013-10-27T13:30:34.010 回答
0

Java 是一种 OO 语言,因此您应该创建自己的对象,而不是仅仅依赖数据结构。这将使一切更容易编写、阅读和维护。

所以你应该有一个Track类,包含一个ListSet一个属性。选择取决于您是否关心属性的顺序,以及是否必须删除重复项。

Track 类应该允许您添加和获取属性,因为这是您需要做的。而且由于您似乎只对曲目感兴趣,而不对第一首曲目之前的行中的其他信息感兴趣,因此您只需要一个曲目列表来保留所有曲目。

所以算法应该很简单:

  • 将行拆分为标记
  • 创建一个空List<Track>
  • 遍历令牌
    • 如果当前令牌是trackstart,则创建一个新的Track,并将这个新Track实例分配给变量currentTrack。将此曲目添加到曲目列表中
    • 如果当前令牌是其他东西,那么
      • 要么currentTrack是空的,你应该忽略令牌
      • orcurrentTrack不为空,您应该通过调用将标记添加为当前轨道的属性currentTrack.addAttribute(token)

在算法结束时,您有一个List<Track>完整的 Track 实例,其顺序与行中的轨道相同。并且每个 Track 实例都有一个List<String>包含该轨道的属性。

于 2013-10-27T13:22:02.553 回答