How to read a file in a while loop that ends with special strings?

时间:2017-08-04 12:49:27

标签: java file

The code example here will be in Java, but I've encountered this problem in C++ and basically anywhere I have to parse such a file. I'm working with parsing strings from a file that come from an electronic design automation software suite. The file is called a "netlist", and it contains information regarding the electronic devices as well as special strings. Here is a sample:

R3 1 4 137 425 1
R4 1 2 60 479 0
R5 2 3 55 596 0
V2 3 4 171 680 1
.end

I have a Java class, Device, which takes in a line of the file and inputs the data into member variables for each device (for instance, the top line is a resistor called R3, connected to nodes 1 and 4 etc). When I get to the .end string, which comes from the EDA software, I obviously cannot parse it into a Device.

I feel like I keep re-writing the same code over and over, and it feels like a serious anti-pattern to me. I use a while loop to read each line, check if it isn't the ".end" string, and then check that again as the condition to leave the loop:

String line = "";
         BufferedReader in;

         in = new BufferedReader(new FileReader(fileName));
         while(line != null && !line.startsWith(".end"))
         {
                line = in.readLine();
                //this feels like an anti-pattern...
                if(!line.startsWith("end"))
                {
                    Device d = new Device();
                    d.parseDeviceData(line);
                    devices.add(d); //devices  is an ArrayList
                }
         }

It's that double check that bothers me. The only way around it that I can think of is to read the first line outside of the while loop, then read each line at the end of the loop, but that doesn't really solve my problem. Why should I have two readLine statements?

So, am I right to think this is an anti-pattern? If so, how do I avoid it?

3 个答案:

答案 0 :(得分:3)

基本上,您希望逐行读取文件,如果到达末尾或者出现以.end开头的行,则停止。您当前的方法确实可以简化,因为第二次检查的结果已经知道了。

我将如何做到这一点:

BufferedReader in;
in = new BufferedReader(new FileReader(fileName));

while (true) {
    String line = in.readLine();
    if (line == null || line.startsWith(".end")) {
        // Abort parsing the file
        break;
    }

    // Valid line, parse it
    Device d = new Device();
    d.parseDeviceData(line);
    devices.add(d);
}

如果您不喜欢while (true),那么您还可以将比较结果保存在变量中。

请注意,我们现在应该使用名为 NIO 的Javas新I / O库。它更强大,更易于使用,并提供更多功能。其主要类别为FilesPaths。特别感兴趣的是Files#readAllLinesFiles#lines,第一个返回List<String>保存文件的完整内容,第二个返回Stream<String>,然后您可以在其中展开完整内容 Lambda表达式的功能

请注意,目前,这两种方法都不是实现“read until”的最佳选择,因为第一种方法会读取整个内容而Stream也不容易< EM>中止。因此, Java 9 将引入方法Stream#takeWhileStream#dropWhile

然而,Stream可以轻松转换为Iterator,并且它们可以再次与常规逻辑一起使用,因此我们可以使用此代码:

Iterator<String> lineIterator = Files.lines(Paths.get(fileName)).iterator();

while (lineIterator.hasNext()) {
    String line = lineIterator.next();
    if (line.startsWith(".end")) {
        // Abort parsing the file
        break;
    }

    // Valid line, parse it
    Device d = new Device();
    d.parseDeviceData(line);
    devices.add(d);
}

答案 1 :(得分:1)

You could put your line scanning bit into the while condition:

while(!(line = in.readLine()).startsWith(".end"))
{
    System.out.println(line);
}

It's not nice looking but it will prevent you from having to test your condition twice. It will become dirtier(really dirty!) if you have many conditions to check though.

答案 2 :(得分:0)

也许我错了,但答案似乎非常简单

     String line = null;
     BufferedReader in;

     in = new BufferedReader(new FileReader(fileName));
     for(;;)
     // instead use while(true) on personal taste / teacher / tradition / :)
     {
            line = in.readLine();
            if(line == null)
            {
                 // break because of eof, wrong end, do something !!!!
                 // throw new XxxxxxxxException("bad end of file")  
                 break;

            }  
            if( line.startsWith(".end") )
            {  
               // correnct end
                break;
            }
            Device d = new Device();
            d.parseDeviceData(line);
            devices.add(d); //devices  is an ArrayList

     }