0

我正在尝试制作文件十六进制转换器(输入文件->输出文件的十六进制字符串)

我想出的代码是

static String open2(String path) throws FileNotFoundException, IOException,OutOfMemoryError {
    System.out.println("BEGIN LOADING FILE");
    StringBuilder sb = new StringBuilder();
    //sb.ensureCapacity(2147483648);
    int size = 262144;
    FileInputStream f = new FileInputStream(path);
    FileChannel ch = f.getChannel( );
    byte[] barray = new byte[size];
    ByteBuffer bb = ByteBuffer.wrap( barray );
    while (ch.read(bb) != -1)
    {
        //System.out.println(sb.capacity());
        sb.append(bytesToHex(barray));
        bb.clear();
    }

    System.out.println("FILE LOADED; BRING IT BACK");
    return sb.toString();
}

我确信“路径”是一个有效的文件名。问题在于大文件 (>= 500mb),编译器在 StringBuilder.append 上输出 OutOfMemoryError: Java Heap Space。

为了创建此代码,我遵循了http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly中的一些提示中的一些提示,但是当我尝试为 StringBuilder sb 强制分配空间时我有疑问:“2147483648 对于 int 来说太大了”。

如果我想在非常大的文件中使用此代码(如果我真的不得不停在某个地方,假设最多 2gb)在速度方面输出文件的十六进制字符串转换的更好方法是什么?


我现在正在将转换后的字符串复制到文件中。无论如何,在原始文件的 eof 之后,我遇到了“在文件上写入空缓冲区”的问题。

static String open3(String path) throws FileNotFoundException, IOException {
    System.out.println("BEGIN LOADING FILE (Hope this is the last change)");
    FileWriter fos = new FileWriter("HEXTMP");
    int size = 262144;
    FileInputStream f = new FileInputStream(path);
    FileChannel ch = f.getChannel( );
    byte[] barray = new byte[size];
    ByteBuffer bb = ByteBuffer.wrap( barray );
    while (ch.read(bb) != -1)
    {
        fos.write(bytesToHex(barray));
        bb.clear();
    }

    System.out.println("FILE LOADED; BRING IT BACK");
    return "HEXTMP";
}

显然,创建的文件 HEXTMP 的大小倍数为 256k,但如果文件为 257k,它将是一个 512 文件,最后 LOT 为“000000”。我知道我只需要创建一个切割长度的最后一个字节数组。

(我使用了文件写入器,因为我想写入十六进制字符串;否则它只会按原样复制文件)

4

3 回答 3

2

为什么要加载完整的文件?

您可以从输入文件加载缓冲区中的几个字节,处理缓冲区中的字节,然后将处理后的字节缓冲区写入输出文件。继续此操作,直到输入文件中的所有字节都未处理。

FileInputStream fis = new FileInputStream("in file");
FileOutputStream fos = new FileOutputStream("out");
byte buffer [] = new byte[8192];
while(true){
  int count = fis.read(buffer);
  if(count == -1)
     break;
  byte[] processed = processBytesToConvert(buffer, count);
  fos.write(processed);
}
fis.close();
fos.close();

所以只需读取缓冲区中的几个字节,将其转换为十六进制字符串,从转换后的十六进制字符串中获取字节,然后将这些字节写回文件,并继续接下来的几个输入字节。

于 2013-10-13T10:05:07.887 回答
0

这里的问题是您尝试读取整个文件并将其存储在内存中。您应该使用流,读取输入文件的一些行,转换它们并将它们写入输出文件。这样,无论输入文件的大小如何,您的程序都可以扩展。

于 2013-10-13T10:06:21.010 回答
0

关键是分块读取文件,而不是一次性读取所有文件。根据其用途,您可以改变块的大小。例如,如果您尝试制作一个十六进制查看器/编辑器,则确定视口中显示了多少内容并从文件中读取尽可能多的数据。或者,如果您只是将十六进制转换并转储到另一个文件,请使用任何足够小以适合内存但足够大以提高性能的块大小。这应该可以在某些运行中进行调整。也许在 Java 7 中使用文件系统 NIO,这样您就可以同时完成所有三个任务——读取、处理和写入。包含在问题中的链接为阅读文件提供了很好的入门知识。

于 2013-10-13T10:07:56.033 回答