【问题标题】:Is there a way to read serialized files using Files.lines in Java 8有没有办法在 Java 8 中使用 Files.lines 读取序列化文件
【发布时间】:2015-12-14 19:54:34
【问题描述】:

我正在尝试读取对象的序列化文件,但我想体验 Java 8 的功能性编程特性;但是,我不断收到 MalformedInputException。显然, Files.lines 读取的是 Stream,而不是对象。 (Files class in Oracle Documentation.) 因此输入格式错误——它无法使用它正在使用的字符集处理字符串的序列化字符。

我通常会使用 ObjectInputStream,但我有心情尝试一些新的东西。 Java 8 中是否缺少允许在 lambdas 上下文中使用流从序列化文件中读取的内容?

如果您有兴趣,这是我在得知它正在创建 Stream 之前所做的尝试(WordDefinitions.dat 是一个序列化文件,其中包含来自我称为定义的类的自定义数据类对象 - 基本上只是用于实验):

List<Definition> defsList =
    Files.lines(Paths.get("WordDefinitions.dat")) 
        .collect(Collectors.toList());

我什至尝试了显式转换:

List<String> defsList =
    Files.lines(Paths.get("WordDefinitions.dat"))
        .map(item -> {
            Definition temp = (Definition)item;
            return temp.toString();
         })
         .collect(Collectors.toList());

【问题讨论】:

  • 不,你没有错过任何东西。没有等效的 Files.lines() 会返回 Stream。我认为这有两个主要原因:1. 将序列化对象保存在文件中并不常见,应该避免 IMO(更喜欢更长期、开放和可维护的解决方案,例如 JSON 或 XML),2. 将对象保存到使用序列化的文件,序列化单个 List 或 Set 对象要容易得多。
  • 谢谢!感谢您的意见。

标签: serialization file-io lambda java-8 java-stream


【解决方案1】:

没有将ObjectInputStream 转换为Stream&lt;Object&gt; 的功能,通常,这些功能不能很好地结合使用。最值得注意的是,ObjectInputStream 没有提供任何方法来识别是否有更多对象可用,即是否已到达流的末尾。

不过,您可以使用以下方法创建流:

public static Stream<Object> fromFile(File f) throws IOException {
    FileInputStream is=new FileInputStream(f);
    try {
        ObjectInputStream ois=new ObjectInputStream(is);
        return StreamSupport.stream(
        new Spliterators.AbstractSpliterator<Object>(Long.MAX_VALUE, Spliterator.ORDERED) {
            public boolean tryAdvance(Consumer<? super Object> action) {
                try {
                    action.accept(ois.readObject());
                    return true;
                } catch (IOException ex) {
                    throw new UncheckedIOException(ex);
                } catch (ClassNotFoundException ex) {
                    throw new NoClassDefFoundError(ex.getMessage());
                }
            }
            @Override public Spliterator<Object> trySplit() { return null; }
        }, false).onClose(() -> { try { ois.close(); }
            catch (IOException ex) { throw new UncheckedIOException(ex); } });
    } catch(Throwable t) {
        try(FileInputStream toClose=is) { throw t; }
    }
}

如前所述,此流不知道其对象数量,因此需要显式使用 limit 以确保不会尝试读取末尾:

File f=File.createTempFile("ser", null);
try(FileOutputStream os=new FileOutputStream(f);
    ObjectOutputStream oos=new ObjectOutputStream(os)) {
    oos.writeObject("hello");
    oos.writeObject(42);
    oos.writeObject(Arrays.asList("X", "Y", "Z"));
    oos.flush();
}
System.out.println(f+": "+f.length()+" bytes");
try(Stream<Object> s=fromFile(f)) {
    s.limit(3).forEach(System.out::println);
}

【讨论】:

  • 哇!真棒答案!这很有帮助!我需要一段时间来学习其中的新概念,但我迫不及待地想解决它们!我听说过 Spliterators,但不知道它们是什么或它们的用途。现在我有充分的理由更仔细地研究它们。而且我从未听说过 StreamSupport 类!非常感谢您分享您的知识!
【解决方案2】:

没有。序列化的对象不是线条。

【讨论】:

  • 是的,我已经想通了,正如我在问题文本中所展示的那样。 JB Nizet 很好地回答了我的问题——“没有等效的 Files.lines() 会返回 Stream”。感谢您的宝贵时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
  • 2014-06-10
相关资源
最近更新 更多