【问题标题】:Optimize way to pass a file for parsing in JAVA优化在JAVA中传递文件进行解析的方式
【发布时间】:2014-06-26 22:01:47
【问题描述】:

我有两个类 getFile 和 readFile。 在 getFile 中有一个方法 gettingFile() 用于获取文件,而在 readFile 类中有一个方法 parseFile() 将解析文件。

public void gettting(){
    File file1= new File("abc.bin");
    ....
    ....
}

我感到困惑的是,将“file1”发送到 parseFile() 方法的最佳方式是什么。 我现在想到的三个选项是:作为文件本身..

parseFile(file1);

或作为 byteArray..

DataInputStream dataIStream= new DataInputStream(new FileInputStream(file1));
BufferedInputStream bin= new BufferedInputStream(dataIStream);
byte[] byteArray= new byte[bin.available()];
bin.read(byteArray);
parseFile(byteArray);

或作为输入流..

parseFile(new FileInputStream(file1));

或者还有比这更好的选择吗? 我要解析的文件大小最大:20KB,最小:1KB。所有文件都是二进制文件,其中包含结构化格式的数据。是的,我能够做到以上任何一种方法。我在想哪个更好。 我将在 android 应用程序中使用这些类 在这里 stackoverflow.com/a/21101403/2508414 它说的是输入流。还是我的理解有误。

【问题讨论】:

  • 你认为最简单的是什么?没有更多信息,就没有明确的“最佳”方式。
  • 请注意,您的数组变体不一定会处理整个文件
  • @PeterLawrey 我要解析的文件大小最大:20KB,最小:1KB。所有文件都是二进制文件。我必须解析它并获取必要的信息
  • @kaze 所以大小不太重要,我会使用你认为最简单的方法。

标签: java android file file-io binaryfiles


【解决方案1】:

您有以下选择:

  • 传递文件
    这意味着您只能处理文件。我不会使用它,除非您需要元数据(名称,大小,...)。此外,传递的文件可能是一个目录,这意味着需要额外检查。
  • 将数据作为字节数组传递
    这需要大量的努力来首先读取数据,并且对于较大的数据也不能很好地扩展(所有数据都必须在内存中) .不推荐。
  • 传递 URL
    这作为文件变体更加灵活,因为它允许传递文件 URL (file.toURI().toURL())、资源 URL (Class.getResource(.. .)) 和网址。然后通过从 URL 打开输入流来读取数据。推荐用于任何资源。
  • 将数据作为 InputStream 传递
    非常灵活,可以从任何东西创建输入流(也可用于测试,允许从字符串创建测试数据)。同样高效,允许数据流。一般推荐。提示:始终将传递的InputStream 包装成BufferedInputStream,这样会大大提高性能。
  • 将数据作为 Reader 传递
    在读取字符数据时,这是使用 InputStream 的推荐替代方法(您需要知道字符编码,或者需要将其作为附加争论)。提示:始终将传递的Reader 包装成BufferedReader,这样会大大提高性能。

如果您编写可重用的 API,我建议提供以下变体:

void parseFile(URL url) // delegate to parseFile(Reader)
void parseFile(InputStream in, String encoding) // delegate to parseFile(Reader)
void parseFile(Reader reader) // parsing code

【讨论】:

  • 所以对于二进制文件,最好的方法是把它作为一个包裹在BufferedIS中的Inputstream传递?因为我必须通过提供给我的数据结构格式(int、char 等)来解析必要的数据。
  • 如果它包含要解析的字符数据,建议将其作为 Reader 传递(允许将数据读取为字符,而不是字节)。 BufferedReader 还允许逐行读取数据,这在读取带有换行符的数据时可能会有所帮助。
  • 我不是在读取文本文件,我正在读取的二进制文件“abc.bin”中的数据是这样编码的,前 2 个字节代表一个整数值,接下来的 5 个bytes 将是文件的名称,下一个字节的值将表示某个对象的数量等等..
  • 如果我在像 parseFile(bin); 这样的gettingFile方法中将它作为输入流传递,并将其作为parseFile(BufferedInputStream bis)捕获我在哪里需要关闭流吗?在 parseFile() 方法或 gettingFile() 方法或两者中?
  • 当从流/阅读器读取直到耗尽(没有更多可用数据)时,最好立即关闭它。这是可选的,因为打开流的一方也负责关闭它。我会使用 try-with-resources (docs.oracle.com/javase/tutorial/essential/exceptions/…)。
【解决方案2】:

我认为正常的方法是传递 File 对象并使用 1 个方法创建和关闭流。

File 对象只不过是一个没有任何关联资源的文件描述符。一旦打开文件的流,就会出现谁负责关闭它的问题。通常我们可以遵循“谁创建资源负责销毁它”,这意味着文件流的打开和关闭应该是在同一个方法中。

如果您想自定义内容的解析,您应该使行解析方法抽象(鉴于您谈论解析,我假设这是纯文本文件)或子类化该部分。

说了这么多,如果你确实在做文本解析,你应该使用 BufferedReader,它既有很多方便的方法,比如 readLine() 也有更好的性能,因为它在内部保留了一个缓冲区,而不是去每次为一个角色流式传输。

【讨论】:

  • 我已经编辑了我的问题,看看。所以,我决定将它作为像 parseFile(bin); 这样的gettingFile方法中的缓冲输入流传递,并将它作为 parseFile(BufferedInputStream bis) 我需要在哪里关闭这些流?在 parseFile() 方法或 gettingFile() 方法或两者中?
【解决方案3】:

只需传递文件并让解析方法根据需要读取它。将其预加载到字节数组中只会浪费时间和空间。

【讨论】:

  • 我已经编辑了我的问题,作为文件对象传递仍然是最好的选择吗?
  • 这里stackoverflow.com/a/21101403/2508414 说的是输入流。还是我的理解有误。
  • 通过FileInputStream,以最适合您的方式,或两者兼而有之,忘记byte[] 选项。
【解决方案4】:

我的观点是有两种的方式来思考这个问题:

  • 直接输入文件既省时又简单易懂
  • 提供字节数组作为输入可以更灵活地确定内容的来源,只要最终将其转换为字节数组,您最终就可以拥有一个从其他地方提供内容的外部服务

我会选择 second 选项,并作为建议尝试 Apache Commons IO 库。它有一个 FileUtils 和 IOUtils 类,提供了一些方便的方法来播放文件和流。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-07
    • 2015-05-15
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2020-03-15
    • 2014-08-22
    • 1970-01-01
    相关资源
    最近更新 更多