使用缓冲读取器读取给定输入的数据块

时间:2018-05-23 11:06:11

标签: java bufferedreader

所以这是我正在阅读的文件的结构:

[MESSAGE BEGIN]
uan:123
messageID: 111
[MESSAGE END]
[MESSAGE BEGIN]
uan:123
status:test
[MESSAGE END]

我想要做的是,对于给定的uan,返回它的所有细节,同时保持块结构" MESSAGE BEGIN" " MESSAGE END"。

这是我写的代码:

startPattern= "uan:123"
endPattern= "[MESSAGE END]"
 System.out.println("Matching: " + this.getStartPattern());
        List<String> desiredLines = new ArrayList<>();

        try (BufferedReader buff = Files.newBufferedReader(getPath())) {
            String line = "";
            while ((line = buff.readLine()) != null) {

                if (line.contains(this.getStartPattern())) {
                    desiredLines.add(line);
                    System.out.println(" \nMatch Found! ");
                    buff.lines().forEach(streamElement -> {
                        if (!streamElement.contains(this.getEndPattern())) {
                            desiredLines.add(streamElement);
                        } else if (streamElement.contains(this.getEndPattern())) {
                            throw new IndexOutOfBoundsException("Exit Status 0");
                        }
                    });

                }

现在,问题是,当看到第一个&#34; uan&#34;并只捕获消息ID。我希望代码还包括&#34; status&#34;当我通过uan时。

任何人都可以帮忙吗?

修改

这是我的预期输出:

 uan:123
 messageID: 111
 uan:123
 status:test

应捕获所有uan:123的实例

3 个答案:

答案 0 :(得分:1)

如何创建,例如Data类,包含给定uan的所有字段?我可以看到你有一个带有id的对象(即uan),并且有很多消息为这个对象。

我提议使用这种方法并在同一个实例中收集所有相关信息(属于uan的同一个对象):

这是Data类:

final class Data {

    private String uan;
    private final List<Map<String, String>> events = new LinkedList<>();

    public Data(String uan) {
        this.uan = uan;
    }

    public String getUan() {
        return uan;
    }

    public boolean hasUan() {
        return uan != null && !uan.isEmpty();
    }

    public void set(Data data) {
        if (data != null)
            events.addAll(data.events);
    }

    public void addEvent(String key, String value) {
        if ("uan".equalsIgnoreCase(key))
            uan = value;
        else
            events.add(Collections.singletonMap(key, value));
    }
}

这是读取给定文件并使用密钥Map<String, Data>检索uan的方法,值是此对象的所有数据:

private static final String BEGIN = "[MESSAGE BEGIN]";
private static final String END = "[MESSAGE END]";
private static final Pattern KEY_VALUE_PATTERN = Pattern.compile("\\s*(?<key>[^:]+)\\s*:\\s*(?<value>[^:]+)\\s*");

private static Map<String, Data> readFile(Reader reader) throws IOException {
    try (BufferedReader br = new BufferedReader(reader)) {
        Data data = null;
        Map<String, Data> map = new TreeMap<>();

        for (String str; (str = br.readLine()) != null; ) {
            if (str.equalsIgnoreCase(BEGIN))
                data = new Data(null);
            else if (str.equalsIgnoreCase(END)) {
                if (data != null && data.hasUan()) {
                    String uan = data.getUan();
                    map.putIfAbsent(uan, new Data(uan));
                    map.get(uan).set(data);
                }

                data = null;
            } else if (data != null) {
                Matcher matcher = KEY_VALUE_PATTERN.matcher(str);

                if (matcher.matches())
                    data.addEvent(matcher.group("key"), matcher.group("value"));
            }
        }

        return map;
    }
}

最后,这就像客户端一样:

Map<String, Data> map = readFile(new FileReader("data.txt"));

答案 1 :(得分:0)

只需使用简单的解析逻辑,只有在看到匹配的uan时才输出数据。我使用布尔变量来跟踪我们是否在给定块内找到了匹配的uan。如果是这样,那么我们输出所有行,否则我们没有操作并跳过所有行。

try (BufferedReader buff = Files.newBufferedReader(getPath())) {
    String line = "";
    String uan = "uan:123";
    String begin = "[MESSAGE BEGIN]";
    String end = "[MESSAGE END]";
    boolean match = false;

    while ((line = buff.readLine()) != null) {
        if (uan.equals(line)) {
            match = true;
        }
        else if (end.equals(line)) {
            match = false;
        }
        else if (!begin.equals(line) && match) {
            System.out.println(line);
        }
    }
}

请注意,我没有进行任何验证,以检查每个BEGIN是否通过正确关闭END进行镜像。如果需要,可以在上面的代码中添加额外的逻辑。

答案 2 :(得分:0)

对过滤后的消息进行分组

你的一般方法似乎很好。而不是嵌套循环,我会将其分解为更简单,更直接的逻辑,如:

String needle = "uan:123";

String startPattern = "[MESSAGE BEGIN]";
String endPattern = "[MESSAGE END]";

List<List<String>>> result = new ArrayList<>();
try (BufferedReader buff = Files.newBufferedReader(getPath())) {
    // Lines and flag for current message
    List<String> currentMessage = new ArrayList<>();
    boolean messageContainedNeedle = false;

    // Read all lines
    while (true) {
        String line = buff.readLine();
        if (line == null) {
            break;
        }

        // Collect current line to message, ignore indicator
        if (!line.equals(endPattern) && !line.equals(startPattern)) {
            currentMessage.add(line);
        }

        // Set flag if message contains needle
        if (!messageContainedNeedle && line.equals(needle)) {
            messageContainedNeedle = true;
        }

        // Message ends
        if (line.equals(endPattern)) {
            // Collect if needle was contained
            if (messageContainedNeedle) {
                result.add(currentMessage);
            }

            // Prepare for next message
            messageContainedNeedle = false;
            currentMessage = new ArrayList<>();
        }
    }
}

阅读和理解更容易。它支持您的消息项以任意顺序。此外,生成的result仍然会在List<List<String>>中对邮件进行分组。如果您仍想要List<String>,则可以轻松地对其进行展平。

得到的结构是:

[
    ["uan:123", "messageID: 111"],
    ["uan:123", "status: test"]
]

现在很容易实现您想要的输出:

// Variant 1: Nested for-each
result.forEach(message -> message.forEach(System.out::println));

// Variant 2: Flat-map
result.stream().flatMap(List::stream).forEach(System.out::println));

// Variant 3: Without streams
for (List<String> message : result) {
    for (String line : message) {
        System.out.println(line);
    }
}

对所有消息进行分组

如果省略flag-part,你可以将所有消息解析为该结构,然后轻松地在它们上流式传输:

public static List<List<String>> parseMessages(Path path) {
    String startPattern = "[MESSAGE BEGIN]";
    String endPattern = "[MESSAGE END]";

    List<List<String>>> result = new ArrayList<>();
    try (BufferedReader buff = Files.newBufferedReader(path)) {
        // Data for current message
        List<String> currentMessage = new ArrayList<>();

        // Read all lines
        while (true) {
            String line = buff.readLine();
            if (line == null) {
                break;
            }

            // Collect current line to message, ignore indicator
            if (!line.equals(endPattern) && !line.equals(startPattern)) {
                currentMessage.add(line);
            }

            // Message ends
            if (line.equals(endPattern)) {
                // Collect message
                result.add(currentMessage);

                // Prepare for next message
                currentMessage = new ArrayList<>();
            }
        }
    }

    return result;
}

用法简单明了。例如,使用"uan:123"

过滤邮件
List<List<String>> messages = parseMessages(getPath());

String needle = "uan:123";
List<List<String>> messagesWithNeedle = messages.stream()
    .filter(message -> message.contains(needle))
    .collect(Collectors.toList());

结果结构又是:

[
    ["uan:123", "messageID: 111"],
    ["uan:123", "status: test"]
]

可以直接在流级联中实现所需的输出:

messages.stream()  // Stream<List<String>>
    .filter(message -> message.contains(needle))
    .flatMap(List::stream)  // Stream<String>
    .forEach(System.out::println);

消息容器

一个自然的想法是将消息数据分组到指定的Message容器类中。这样的事情:

public class Message {
    private final Map<String, String> mProperties;

    public Message() {
        mProperties = new HashMap<>();
    }

    public String getValue(String key) {
        return mProperties.get(key);
    }

    public void put(String key, String value) {
        mProperties.put(key, value);
    }

    public static Message fromLines(List<String> lines) {
        Message message = new Message();
        for (String line : lines) {
            String[] data = line.split(":");
            message.put(data[0].trim(), data[1].trim());
        }
        return message;
    }

    // Other methods ...
}

请注意方便的Message#fromLines方法。使用它可以获得List<Message>并使用数据更方便。