如何使用ByteStream将1Mb文件读入字符串

时间:2013-10-25 20:38:22

标签: java guava readfile

我现在拥有的是使用FileInputStream

int length = 1024*1024;
FileInputStream fs = new FileInputStream(new File("foo"));
fs.skip(offset);
byte[] buf = new byte[length];
int bufferSize = fs.read(buf, 0, length);
String s = new String(buf, 0, bufferSize);

我想知道如何在guava库中使用ByteStreams来实现相同的结果。

非常感谢!

3 个答案:

答案 0 :(得分:3)

以下是你如何用Guava做到的:

byte[] bytes = Files.asByteSource(new File("foo"))
    .slice(offset, length)
    .read();
String s = new String(bytes, Charsets.US_ASCII);

您的代码存在一些问题(尽管它可能适用于文件,但不一定适用于任何类型的流):

fs.skip(offset);

这不一定会跳过所有offset个字节。您必须检查它在返回值中跳过的字节数,直到您跳过全部金额或使用为您执行此操作的内容,例如ByteStreams.skipFully

int bufferSize = fs.read(buf, 0, length);

同样,这不一定会读取所有length字节,并且它读取的字节数可以是任意数量 - 一般情况下不能依赖它。

String s = new String(buf, 0, bufferSize);

这隐含地使用系统默认Charset,这通常不是一个好主意 - 当你想要它时,最好用Charset.defaultCharset()明确它。

另请注意,一般情况下,一定数量的字节可能无法转换为合法的字符序列,具体取决于所使用的Charset(例如,如果它是ASCII,那么你很好,如果它是Unicode,那么这么多)。

答案 1 :(得分:1)

为什么在没有必要时尝试使用番石榴?

在这种情况下,看起来你正在寻找一个RandomAccessFile。

File file = new File("foo");
long offset = ... ;
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
  byte[] buffer = new byte[1014*1024];
  raf.seek(offset);
  raf.readFully(buffer);
  return new String(buffer, Charset.defaultCharset());
}

答案 2 :(得分:0)

我不知道更优雅的解决方案:

public static void main(String[] args) throws IOException {
    final int offset = 20;
    StringBuilder to = new StringBuilder();

    CharStreams.copy(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
        @Override
        public InputStream getInput() throws IOException {
            FileInputStream fs = new FileInputStream(new File("pom.xml"));

            ByteStreams.skipFully(fs, offset);

            return fs;
        }
    }, Charset.defaultCharset()), to);

    System.out.println(to);
}

唯一的好处是,当String非常大时,您可以通过避免转换为String来节省一些GC时间。