`

FileInputStream,FileOutputStream和RandomAccessFile 获取的FileChannel

 
阅读更多
package io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.NonReadableChannelException;
import java.nio.channels.NonWritableChannelException;

/**
 * 
 * FileChanel是NIO中的类,NIO称为新 I/O,使用了更接近操作系统执行I/O的方式:通道和缓冲器.
 * 
 * 即先打开一个通道,然后创建一个缓冲器,将通道和缓冲器关联.通道是双向的,既可以读也可以写.
 * 从通道中读取数据时,先把数据读入缓冲器,然后从缓冲器中获取数据;
 * 往通道中写数据时,先把数据写入缓冲器,然后再从缓冲器中将数据写入通道.
 * 
 * 新I/O出来后,还修改了旧IO包中的三个类,FileInputStream,FileOutputStream和RandomAccessFile.
 * 通过这三个类的getChannel()返回一个FileChannel通道.
 * 
 * 注意,上文说了Channel是双向的,即,可以读,也可以写(FileChannel有read和write方法).
 * 这个对于RandomAccessFile返回的FileChannel来说,不是很奇怪.
 * 
 * 但是对于 使用 FileInputStream 返回的FileChannel来写(write),
 * 或者使用FileOutputStream返回的FileChannel来读(read)
 * 的话,就有些奇怪了.
 * 
 * 为了排除疑问,使用下面的代码测试之.
 * 测试结果:
 * (1)FileInputStream 生成的FileChannel是只读的,尝试写入是抛异常:NonWritableChannelException
 * (2)FileOutputStream 生成的FileChannel只能写入,并且一旦建立这个对象,则与之关联的文件内容被清空.
 * 如果尝试读取获取的FileChannel的内容,则抛异常:NonReadableChannelException
 * (3)由RandomAccessFile获取的FileChannel则仍旧可读可写.
 *
 */

public class TestFileChanel
{
  public static void main(String[] args) throws IOException
  {
    boolean bInputChannel = false;
    boolean bOutputchannel = false;
    boolean bRandomAccessChannel = true;

    // 首先,使用RandomAccessFile创建一个4*4字节的文件(相当于存入4个int型的0)
    File f = new File("D:\\D\\test_channel.dat");
    // 如果文件存在,先删除之,比较暴力,需要确保D:\\D\\test_channel.dat 这个文件不存在
    if (f.exists())
    {
      f.delete();
    }

    RandomAccessFile rf = new RandomAccessFile(f, "rw");
    rf.setLength(4 * 4);  //4 个 int 的容量
    rf.writeInt(1); //前4个字节 写入整型的 1
    rf.seek(3 * 4); //position移动到第3个整型(3*4 = 12)之后,
    rf.writeInt(5);// 最后4个字节 写入一个整型的5
    rf.close();
    // 完成之后,使用UE打开这个二进制文件,可见文件结构如下(|分隔符不存在的,这里为了方便阅读):
    // 00 00 00 01 | 00 00 00 00 | 00 00 00 00 | 00 00 00 05

    FileChannel fc = new RandomAccessFile(f, "rw").getChannel();
    if (bRandomAccessChannel)
    {
      System.out.println("------使用RandomAccessFile返回的FileChannel--------");
      // 测试使用FileOutputStream返回的FileChannel 从 上面文件的文件中 读取 一个int(4字节)
      fc = new RandomAccessFile(f, "rw").getChannel();
      try
      {
        fc.position(4);// 文件通道位置设置到第5个字节之前,第4个字节之后
        //00 00 00 01 $ 00 00 00 00 | 00 00 00 00 | 00 00 00 05
        //此时position 在上面的$处,注意 这里是文件的position
        
        ByteBuffer ib = ByteBuffer.allocate(8);//分配一个buffer 8字节(capacity = 8),且全部初始化为0了
        //可以认为此时的buffe结构向下面这个样子
        // $ 00 00 00 01 | 00 00 00 00
        // $为初始化后position位置, | 是分隔符 便于阅读,此时limit等于capacity
        
        System.out.printf("buffer ByteBuffer.allocate(8) 初始化完毕之后%nposition=%1$d,limit=%2$d %n",ib.position(),ib.limit());

        // 先写一个整数7
        System.out.printf("buffer 在put之前,position=%1$d %n",ib.position());
        ib.asIntBuffer().put(7);
        System.out.printf("buffer 在put之后,position=%1$d %n",ib.position());
        //此时buffer格式为:
        //$ 00 00 00 07 | 00 00 00 00
        //注意:此时buffer的position并没有因为put而向前移动了,仍然在开头位置.
        
        ib.limit(ib.position() + 4);
        //限制只写入buffer中的00 00 00 07 这个数据,即写入整型的7到文件
        fc.write(ib);
        System.out.println("写入后,buffer的position:" + ib.position());//写入后,buffer的position:4
        //此时buffer格式为:
        // 00 00 00 07 $ 00 00 00 00
        // 注意,因Channel 将Buffer中的的数据写入,
        //导致写入后buffer的position从之前的位置(0)移动了一个limit的位置(4)
        
        fc.force(true);//强制将所有对此通道的文件更新写入包含该文件的存储设备中。
        System.out.printf("写入完成后,文件通道位置为:%1$d,buffer位置为:%2$d %n" , fc.position(),ib.position());
        //写入完成后,文件通道位置为:8,buffer位置为:4
        //写入后,文件的二进制数据如下:
        //00 00 00 01 | 00 00 00 07 $ 00 00 00 00 | 00 00 00 05
        //写入完成后,buffer数据如下:
        //00 00 00 07 $ 00 00 00 00

        System.out.printf("调用clear()之 前,buffer位置为:%1$d,limit为:%2$d %n" ,ib.position(),ib.limit());
        ib.clear(); //清空buffer,将位置设置为 0,将限制设置为容量,并丢弃标记
        
        // 测试从通道中读一个整数
        System.out.printf("调用clear()之后,buffer位置为:%1$d,limit为:%2$d %n" ,ib.position(),ib.limit());
        //调用clear()之后,buffer位置为:0,limit为:8
        //此时buffer数据如下:
        // $ 00 00 00 00 | 00 00 00 00
        fc.read(ib);
        
        
        //read的时候从Channel(fc)的当前位置开始read,此时Channel(fc)的位置为8
        System.out.printf("调用fc.read(ib)读取之后,buffer位置为:%1$d %n" ,ib.position());
        //调用fc.read(ib)读取之后,buffer位置为:8
        //注意read之后,如果文件内容大于buffer,read limit - position 个字节,并从position填充到limit
        //此时buffer内容为:
        // 00 00 00 00 | 00 00 00 05 $
        
        System.out.printf("调用fc.read(ib)读取之后,文件通道fc的位置为:%1$d %n" ,fc.position());
        //
        
        ib.position(4);
        //将buffer的position提前4,读取最后一个整数,否则报java.nio.BufferUnderflowException 异常
        //此时buffer内容为:
        // 00 00 00 00 $ 00 00 00 05
        int iTmp = ib.asIntBuffer().get();//读取了00 00 00 05
        System.out.printf("调用ib.asIntBuffer().get()之后,buffer位置为:%1$d %n" ,ib.position());
        //调用ib.asIntBuffer().get()之后,buffer位置为:4 
        System.out.println(iTmp); //输出5

      }
      catch (NonReadableChannelException e)
      {
        System.out.println("通道不可读");
      }
      finally
      {
        fc.close();
      }
    }
    
    if (bInputChannel)
    {
      System.out.println("------使用FileInputStream返回的FileChannel--------");
      // 接下来,测试使用FileInputStream返回的FileChannel往上面文件的文件中写入一个int(4字节)
      fc = new FileInputStream(f).getChannel();
      try
      {
        fc.position(4);// 通道位置设置到第5个字节之前,第4个字节之后
        ByteBuffer ib = ByteBuffer.allocate(4);

        // 测试从通道中读一个整数
        int iTmp = ib.asIntBuffer().get();
        System.out.println(iTmp); // 可以读出一个int

        ib.clear();

        ib.asIntBuffer().put(7);
        fc.write(ib); // 执行时报错,抛NonWritableChannelException异常,
        //说明FileInputStream(f).getChannel()方法获取的通道是不可写的.

      }
      catch (NonWritableChannelException e)
      {
        System.out.println("通道不可写");
      }
      finally
      {
        fc.close();
      }
    }
    
    if (bOutputchannel)
    {
      System.out.println("------FileOutputStream返回的FileChannel--------");
      fc = new FileOutputStream(f).getChannel();//调用这个之后,原来的文件内容被清空了,等着write
      
      // 测试使用FileOutputStream返回的FileChannel 从 上面文件的文件中 读取 一个int(4字节)
      try
      {
        fc.position(4);// 通道位置设置到第5个字节之前,第4个字节之后
        ByteBuffer ib = ByteBuffer.allocate(16);

        // 先写一个整数7
        ib.asIntBuffer().put(7);
        fc.write(ib);
        fc.force(true);
        ib.flip();

        ib.clear();
        // 测试从通道中读一个整数
        fc.read(ib); // 抛出异常 NonReadableChannelException
      }
      catch (NonReadableChannelException e)
      {
        System.out.println("通道不可读");
      }
      finally
      {
        fc.close();
      }
    }
  }
}

 

分享到:
评论

相关推荐

    【IT十八掌徐培成】Java基础第26天-06.FileChannel-RandomAccessFile-CopyFile.zip

    通过`FileInputStream`, `FileOutputStream`, `ServerSocketChannel`, `SocketChannel`等可以获取`FileChannel`实例。例如,我们可以使用`FileInputStream`的`getChannel()`方法来创建一个`FileChannel`。 ```java ...

    Java流和文件总结(二)

    文件通道(FileChannel)可以从FileInputStream, FileOutputStream或RandomAccessFile获取,支持随机访问文件。MappedByteBuffer允许将文件映射到内存,使得文件操作如同操作内存一样高效。 Java的IO库还提供了对象...

    java实现文件批处理

    在Java中,可以使用`java.io`包中的`FileInputStream`和`FileOutputStream`类来实现文件的复制。首先创建一个输入流读取源文件,然后创建一个输出流写入目标文件。通过循环读取源文件的数据并写入目标文件,可以完成...

    FileLock进程互斥

    要使用`FileLock`,首先需要创建一个`FileChannel`对象,通过`RandomAccessFile`或`FileInputStream`、`FileOutputStream`的`getChannel()`方法获取。然后,可以调用`FileChannel`的`lock()`或`tryLock()`方法来尝试...

    java NIO原理和使用

    这里创建了一个 `RandomAccessFile` 对象,并通过其 `getChannel()` 方法获取了对应的 `FileChannel`。 ##### 2. Buffer (缓冲区) 缓冲区是 Java NIO 中用于存储数据的对象,所有数据都是通过缓冲区进行读写。缓冲...

    Java使用RandomAccessFile类对文件进行读写

    与标准的`FileInputStream`和`FileOutputStream`不同,`RandomAccessFile`不仅支持顺序读写,还能直接跳转到文件的任意位置进行读写,这得益于它的文件指针概念。 1. **RandomAccessFile类简介** `...

    Java中用内存映射处理大文件的实现代码

    最后,记得关闭FileChannel和RandomAccessFile以释放资源。 对比实验中,我们使用了FileInputStream、BufferedInputStream以及RandomAccessFile分别进行文件读取,可以看到,使用内存映射文件(MappedByteBuffer)...

    java io 系列操作代码练习 Java学习资料

    1. FileInputStream和FileOutputStream:分别用于读取和写入文件的字节流。 2. FileReader和FileWriter:它们是字符流,用于读写文本文件。 3. BufferedReader和BufferedWriter:这两个是缓冲字符流,提供缓冲区来...

    【IT十八掌徐培成】Java基础第27天-01.MappedMemoryBuffer-文件内存映射缓冲区.zip

    FileChannel可以从RandomAccessFile、FileInputStream或FileOutputStream中获取。 3. **MappedByteBuffer的创建**:使用FileChannel的map()方法,传入适当的模式(READ_ONLY, READ_WRITE或PRIVATE)和偏移量,可以...

    JavaIODemo-master.zip

    例如,FileInputStream和FileOutputStream用于文件读写,BufferedReader和PrintWriter则提供了缓冲和格式化输出的功能。 2. **缓冲区技术**:Java中的Buffer类(如ByteBuffer、CharBuffer等)提高了I/O性能,通过...

    java文件锁的实现

    `FileChannel`可以从`FileInputStream`, `FileOutputStream`, `RandomAccessFile`等类获得,用于读写文件。创建一个`FileChannel`对象是获取文件锁的第一步。 ```java FileInputStream fis = new FileInputStream(...

    JAVA文件操作大全

    - **字节流**:FileInputStream和FileOutputStream处理字节数据,适用于任何类型的数据。如`new FileInputStream("file.txt")` 创建一个FileInputStream对象。它们也可以与BufferedInputStream/...

    Java IO 工具类大全

    四、FileInputStream和FileOutputStream 这两个类分别用于读写文件的字节流。例如,你可以使用FileInputStream的`read()`方法逐字节读取文件,FileOutputStream的`write()`方法写入字节。为了提高效率,通常会结合...

    Java IO处理类的汇总

    更高级的文件操作可以使用FileChannel和RandomAccessFile,它们支持随机访问和大块数据传输。 NIO(New IO)是Java 1.4引入的扩展,提供了非阻塞I/O、选择器和内存映射文件等特性,提升了并发性能。Channels代表...

    java读写文件的集中方式

    `FileInputStream`和`FileOutputStream`是用于字节流操作的基础类,它们适用于读写二进制文件,如图片或音频文件。通过`read()`方法可以读取单个字节,或者使用`read(byte[])`方法一次性读取多个字节。例如: ```...

    FileRW.rar_文件读取

    对于文件读取,我们将使用它们的子类,如`FileInputStream`和`FileOutputStream`。`FileInputStream`用于读取文件,而`FileOutputStream`用于写入文件。以下是如何使用`FileInputStream`读取文件的基本示例: ```...

    java io最简java io

    - **字节流**: 处理字节数据,包括`InputStream`和`OutputStream`家族,如`FileInputStream`和`FileOutputStream`。 - **字符流**: 处理字符数据,基于Unicode编码,包括`Reader`和`Writer`家族,如`FileReader`和...

    javaIO学习课件 很详细的讲解

    FileInputStream和FileOutputStream用于文件的基本读写,而RandomAccessFile则支持随机访问文件的任意位置进行读写。高级的文件操作,如文件复制,可以使用NIO(New IO)的Channels和Buffers来实现,这通常比传统的...

    Java的io的应用

    13. **FileChannel和MappedByteBuffer**: FileChannel允许直接映射文件到内存,使用MappedByteBuffer可以高效地处理大文件。 14. **FilterStream**: FilterInputStream和FilterOutputStream是过滤流,可以作为...

Global site tag (gtag.js) - Google Analytics