为什么访问随机访问文件会导致Java平台崩溃?

时间:2012-01-11 14:05:44

标签: java file

编辑,已解决: 分辨率:

步骤1:确保搜索方法进入正确的位置并使用正确的字节长度写入。修正了几个寻找误导。

第2步:将java和jgrasp更新到最新版本。修复了java崩溃但开始收到主要 - 次要不匹配错误。

第3步:进入jgrasp控件shell,打开启动设置并选择升级后的jre 错误已解决


我正在编写一个程序来读取随机访问文件中的自定义对象(患者)。目前虽然我只是将单个组件(两个字符串,3个整数和一个双字母)写入文件而不是对象本身。它工作得很好,一切仍然编译,但后来我实现了writePatientWeight后开始收到java.exe崩溃消息。我试过评论新的方法,但它仍然崩溃。

   import java.io.*; 
   public class randomTest extends randomAccessMethods{
   public static void main (String args[])throws IOException{
     RandomAccessFile test=createNewFile("test", "rw");
     writePatientID(test, 1234567891);
     writePatientFName(test, "Derrick");
     writePatientLName(test, "Hollenbeck");
     writePatientAge(test, 18);
     writePatientRisk(test, 10);
     writePatientWeight(test, 155);
     test.seek(0);
     int i=test.readInt();
     System.out.println(i);
     test.seek(40);
     String fname=test.readUTF();
     System.out.println(fname);
     test.seek(57);
     String lname=test.readUTF();
     System.out.println(lname);
     test.seek(81);
     int age=test.readInt();
     System.out.println(age);
     test.seek(93);
     int risk=test.readInt();
     System.out.println(risk);
     test.seek(101);
     double weight=test.readDouble();
     System.out.println(weight);
  }
}

randomAccessMethods类:

   import java.io.*;
public class randomAccessMethods extends CriticalPatientQueue{
  public static RandomAccessFile createNewFile(String name, String readwrite) throws IOException{
     if(readwrite!= "r"){//insures that there is a usable read/write variable, defaults to "rw" if there isn't
        if(readwrite!= "w"){
           if(readwrite!= "rw"){
              readwrite="rw";
           }
        }
     }
     RandomAccessFile file=new RandomAccessFile(name+".dat", readwrite);
     return file;
  }

  public static void writePatientID(RandomAccessFile file, int id)throws IOException{
     file.seek(0);  
     file.writeInt(id);//writes the ID to the file, uses 40 bytes(id will always be length 10)
  }

  public static void writePatientFName(RandomAccessFile file, String fname)throws IOException{
     file.seek(40);
     file.writeUTF(fname);//writes the name to the file, uses 17 bytes(fname will always be length 15 + 2 for overhead)
     for(int i=0; i<(17-fname.length()); i++){
        file.writeUTF(" ");
     }
  }

  public static void writePatientLName(RandomAccessFile file, String lname)throws IOException{
     file.seek(57);
     file.writeUTF(lname);//writes the name to the file, uses 24 bytes(fname will always be length 22 + 2 for overhead)
     for(int i=0; i<(22-lname.length()); i++){
        file.writeUTF(" ");
     }
  }

  public static void writePatientAge(RandomAccessFile file, int age)throws IOException{
     file.seek(81);  
     file.writeInt(age);//writes the age to the file, uses 12 bytes(age will always be length 3)
  }

  public static void writePatientRisk(RandomAccessFile file, int risk)throws IOException{
     file.seek(93);  
     file.writeInt(risk);//writes the risk value to the file, uses 8 bytes(risk will always be length 2)
  }

  public static void writePatientWeight(RandomAccessFile file, double weight)throws IOException{
     file.seek(101);
     file.writeDouble(weight);//writes the weight to the file, uses 24 bytes(weight will always be length 3 for overhead) 
  }
}

3 个答案:

答案 0 :(得分:1)

你似乎已经做出了一些不正确的假设。当您编写int时,它将始终采用相同的字节数。例如:

public static void writePatientAge(RandomAccessFile file, int age)throws IOException{
 file.seek(81);  
 file.writeInt(age);//writes the age to the file, uses 12 bytes(age will always be length 3)
}

实际上,当这样写出时,int总是会使用4个字节。请参阅documentation

  

将int作为四个字节写入文件,高字节优先。写操作从文件指针的当前位置开始。

我猜这种错误会导致您遇到的问题。您应该使用适当的值替换所有常量和搜索(例如,假设int在使用writeInt的任何地方都是4个字节,类似地double是8个字节。)

答案 1 :(得分:1)

没有崩溃的堆栈痕迹很难推测。我会尝试使用Java 6 update 30或Java 7 update 2来确保它不是JVM中的错误。


您需要了解每个字段实际使用的字节数。

int总是使用4个字节。

writeUTF()为长度写入2个字节,然后是字符串UTF-8编码。这意味着一些字符使用2和3个字节。如果你正在使用seek(),就我所见,没有任何点填充字段的结尾。 writeUTF(" ")写入三个字节。

我不会使用这么多幻数,试着将你的常数保存在一个地方并使用基本位置的偏移量,这样你就可以有多个记录。

最后,我使用内存映射文件,因为它可以快30倍。这是因为你可以避免在每个字段上进行系统调用(你只有一个映射字节缓冲区的系统调用)我使用1 GB ByteBuffers的列表(2 int的最大功率可以有)

这是我创建映射的8 TB文件内存的示例。 http://vanillajava.blogspot.com/2011/12/using-memory-mapped-file-for-huge.html

使用此方法,您可以读取/写入在50 - 200 ns内持久保存到磁盘的记录。

答案 2 :(得分:0)

我建议使用serialization/deseralization而不是单独写/读每个字段。通过这种技术,您可以在磁盘文件中写入和读取对象。