java - 读写文件的性能,哪个最好?序列化 X Java.nio

标签 java performance serialization

我有一个包含 1 个 int 和 4 个 double 的对象。

我比较了使用序列化和 FileChannel 对象在文件中写入 500 万个此类对象的性能。

在序列化中使用了如下方法来读写文件。

    public void print() throws IOException, ClassNotFoundException{     
    ObjectInputStream input = new ObjectInputStream(new FileInputStream(this.filePath) );                   
    try {           
        while(true) {               
            this.sb = (Sbit) input.readObject();
            //System.out.println(this.sb.toString());
        } 
    }
    catch ( EOFException eofException ) {
        return; 
    } 
    catch (IOException ioException) {
        System.exit( 1 );
    }
    finally {
        if( input != null )
            input.close();
    } 

}   

public void build() throws IOException {        
    ObjectOutputStream output = new ObjectOutputStream( new FileOutputStream(this.filePath) );
    try {           
        Random random = new Random();
        for (int i = 0; i<5000000; i++) {
            this.sb = new Sbit();
            this.sb.setKey(i);
            this.sb.setXMin( random.nextDouble() );
            this.sb.setXMax( random.nextDouble() );
            this.sb.setYMin( random.nextDouble() );
            this.sb.setYMax( random.nextDouble() );

            output.writeObject(this.sb);
        }           
    } 
    catch (IOException ioException) {
        System.exit( 1 );
    } 
    finally {
        try {
            if( output != null)
                output.close();
        }
        catch ( Exception exception ) {
            exception.printStackTrace();
            System.exit(1);
        }
    }       
} 

使用 java.nio 时是:

    public void print() throws IOException {    
    FileChannel file = new RandomAccessFile(this.filePath, "rw").getChannel();  
    ByteBuffer[] buffers = new ByteBuffer[5];
    buffers[0] = ByteBuffer.allocate(4);   // 4 bytes to int
    buffers[1] = ByteBuffer.allocate(8);   // 8 bytes to double
    buffers[2] = ByteBuffer.allocate(8);    
    buffers[3] = ByteBuffer.allocate(8);   
    buffers[4] = ByteBuffer.allocate(8);   

    while (true) {
        if(file.read(buffers[0]) == -1 )       // Read the int, 
            break;                                  // if its EOF exit the loop

        buffers[0].flip();

        this.sb = new Sbit();
        this.sb.setKey(buffers[0].getInt());

        if(file.read(buffers[1]) == -1) {   // Read the int primary value
            assert false;                   // Should not get here!
            break;                          // Exit loop on EOF
        }
        buffers[1].flip();

        this.sb.setXMin( buffers[1].getDouble() );

        if(file.read(buffers[2]) == -1) {   
            assert false;                   
            break;                          
        }
        buffers[2].flip();

        this.sb.setXMax( buffers[2].getDouble() );

        if(file.read(buffers[3]) == -1) {   
            assert false;                   
            break;                          
        }
        buffers[3].flip();

        this.sb.setYMin( buffers[3].getDouble() );
        if(file.read(buffers[4]) == -1) {   
            assert false;                   
            break;                          
        }
        buffers[4].flip();

        this.sb.setYMax( buffers[4].getDouble() );

        for(int i = 0; i < 5; i++)
            buffers[i].clear();

    } 

} 


public void build() throws IOException {    
    FileChannel file = new RandomAccessFile(this.filePath, "rw").getChannel();      

    Random random = new Random();
    for (int i = 0; i<5000000; i++) {
        this.sb = new Sbit();
        this.sb.setKey(i);
        this.sb.setXMin( random.nextDouble() );
        this.sb.setXMax( random.nextDouble() );
        this.sb.setYMin( random.nextDouble() );
        this.sb.setYMax( random.nextDouble() );

        ByteBuffer[] buffers = new ByteBuffer[5];
        buffers[0] = ByteBuffer.allocate(4);   // 4 bytes to into
        buffers[1] = ByteBuffer.allocate(8);   // 8 bytes to double
        buffers[2] = ByteBuffer.allocate(8);   
        buffers[3] = ByteBuffer.allocate(8);   
        buffers[4] = ByteBuffer.allocate(8);   

        buffers[0].putInt(this.sb.getKey()).flip(); 
        buffers[1].putDouble(this.sb.getXMin()).flip();
        buffers[2].putDouble(this.sb.getXMax()).flip();
        buffers[3].putDouble(this.sb.getYMin()).flip();
        buffers[4].putDouble(this.sb.getYMax()).flip();
        try {
            file.write(buffers);
        } 
        catch (IOException e)   {
            e.printStackTrace(System.err);
            System.exit(1);
        } 

        for(int x = 0; x < 5; x++)
            buffers[x].clear();

    }
}

但是我在 java.nio 上阅读了很多相关内容并尝试使用它,正是因为它具有更好的性能。但我的情况并非如此。

写入文件如下(java.nio):

文件大小:175 MB 时间(以毫秒为单位):57638

使用序列化:

文件大小:200 MB 时间(以毫秒为单位):34504

对于这个文件的读取,如下(java.nio):

时间(以毫秒为单位):78172

使用序列化:

时间(以毫秒为单位):35288

我在 java.nio 中做错了什么吗?我想写入与完成相同的二进制文件。还有另一种方法可以有效地写入文件吗?实际上序列化对象是最好的方法吗?

谢谢。

最佳答案

您正在创建 25,000,000 个 ByteBuffer 对象,每个 ByteBuffer 最多为 8 个字节。这是非常低效的。

通过将其分配给循环外的 38 个字节(在 for 语句之前)来创建一个 ByteBuffer

在循环内,您可以使用相同的 ByteBuffer,如下所示:

  buffer.clear();

  buffer.putInt(this.sb.getKey()); 
  buffer.putDouble(this.sb.getXMin());
  buffer.putDouble(this.sb.getXMax());
  buffer.putDouble(this.sb.getYMin());
  buffer.putDouble(this.sb.getYMax());

  buffer.flip();

  try
  {
     file.write(buffer);
  }
  catch (IOException ex)
  {
     ex.printStackTrace();
     //etc...
  }

  buffer.flip();

尝试一下,如果您发现任何改进,请告诉我们。

关于java - 读写文件的性能,哪个最好?序列化 X Java.nio,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9711140/

相关文章:

java - 即使 JAVA_HOME 设置为 JDK11,maven 也采用 Java 1.5 默认值

java - 如何正确构建应用程序结构来使用资源?

c# - Json.net getter 属性未序列化

java - 扩展实现 Serialized 的类

c++用std::string读写结构数组到二进制文件

java - Gen-Class 不生成 .class 文件

java - java 9 中 javax.activation 包的替代品是什么?

python - 如何有效地从多个列表中获取一组唯一值 (Python)

C++ 替换 C99 VLA(目标 : preserve performance)

database - KD-Trees 和缺失值(向量比较)