ThinkJava-新IO

package com.java.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class GetChannel {
      private static final int BSIZE = 1024;
      
      @SuppressWarnings("resource")
      public static void main(String[] args) throws Exception {
              // 获取通道,该通道允许写操作
            FileChannel fc = new FileOutputStream("data.txt").getChannel();
            // 将字节数组包装到缓冲区中
            fc.write(ByteBuffer.wrap("Some text ".getBytes()));
            // 关闭通道
            fc.close();
            
            // 随机读写文件流创建的管道
            fc = new RandomAccessFile("data.txt", "rw").getChannel();
            // fc.position()计算从文件的开始到当前位置之间的字节数
            // 设置此通道的文件位置,fc.size()此通道的文件的当前大小,该条语句执行后,通道位置处于文件的末尾
            fc.position(fc.size()); // Move to the end
            fc.write(ByteBuffer.wrap("Some more".getBytes()));
            fc.close();
            
            // Read the file:
            fc = new FileInputStream("data.txt").getChannel();
            ByteBuffer buff = ByteBuffer.allocate(BSIZE);
            // 将文件内容读到指定的缓冲区中
            fc.read(buff);
            //buffer.flip();一定得有,如果没有,就是从文件最后开始读取的,当然读出来的都是byte=0时候的字符。
            //通过buffer.flip();这个语句,就能把buffer的当前位置更改为buffer缓冲区的第一个位置。
            buff.flip();
            while(buff.hasRemaining()){
                System.out.print((char)buff.get());
            }
      }
}
View Code
对于只读访问,我们必须显式地使用静态的allocate()方法来分配ByteBuffer。 nio的目标就是快速移动大量数据,因此ByteBuffer的大小就显得尤为重要一一实际上,这里使用的lK可能比我们通常要使用的小一点(必须通过实际运行应用程序来找到最佳尺寸).
 
一旦调用read()来告知FileChannel向ByteBuffer存储字节,就必须调用缓冲器上的flip(). 让
它做好让别人读取字节的准备(是的,这似乎有一点拙劣,但是请记住,它是很拙劣的,但却
适用于在取最大速度) 如果我们打算使用缓冲器执行进一步的read()操作,我们也必须得调用
clear()来为每个read()做好准备.这在下面这个简单文件复制程序中可以看到:
 
package com.java.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelCopy {
      private static final int BSIZE = 1024;
      public static void main(String[] args) throws Exception {
            if(args.length != 2) {
              System.out.println("arguments: sourcefile destfile");
              System.exit(1);
            }
            FileChannel in = new FileInputStream(args[0]).getChannel(),
                        out = new FileOutputStream(args[1]).getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
            while(in.read(buffer) != -1) {
              buffer.flip();     // Prepare for writing
              out.write(buffer);
              buffer.clear();    // Prepare for reading
            }
       }
}
View Code
可以看到,打开~个FileChannel以用于读,而打开另一个以用于写。ByteBuffer被分配了
空间,当FileChannel.read()返回- 1时(一个分界符,毋庸置疑,色源于Unix和C) .表示我们已
经到达了输入的末尾。每次read()操作之后,就会将数据输入到缓冲器中. flip()则是准备缓冲器
以便它的信息可以由write()提取. write()操作之后,信息仍在缓冲器中,接着clear()操作则对所
有的内部指针重新安排,以便缓冲器在另一个read()操作期间能够做好接受数据的准备。
 
然而,上面那个程序并不是处理此类操作的理想方式.特殊方法transferTo()和transferFrom()则允许我们将一个通道和另一个通道直接相连:
package com.java.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

public class TransferTo {
      public static void main(String[] args) throws Exception {
            if(args.length != 2) {
              System.out.println("arguments: sourcefile destfile");
              System.exit(1);
            }
            FileChannel in = new FileInputStream(args[0]).getChannel(),
                        out = new FileOutputStream(args[1]).getChannel();
            
            in.transferTo(0, in.size(), out);
            // Or:
            // out.transferFrom(in, 0, in.size());
      }
}
View Code
1 转换数据          
回过头看GetChannel.java这个程序就会发现,为了输出文件中的信息,我们必须每次只读
取一个字节的数据,然后将每个byte类型强制转换成char类型。这种方法似乎有点原始-一如果
我们查看一下java.nio.CharBuffer这个类,将会发现它有一个toString()方法是这样定义的: "返
回一个包含缓冲器中所有字符的字符串。"既然ByteBuffer可以看作是具有asCharBuffer()方法
的CharBuffer ,那么为什么不用它呢?正如下面的输出语句中第一行所见,这种方法并不能解
决问题:
package com.java.io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

public class BufferToText {
    private static final int BSIZE = 1024;
    
    @SuppressWarnings("resource")
    public static void main(String[] args) throws Exception {
        FileChannel fc = new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text".getBytes()));
        fc.close();
        fc = new FileInputStream("data2.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip();
        // Doesn't work:
        System.out.println(buff.asCharBuffer());
        
        // Decode using this system's default Charset:
        buff.rewind();
        String encoding = System.getProperty("file.encoding");
        System.out.println("Decoded using " + encoding + ": " + Charset.forName(encoding).decode(buff));
        
        // Or, we could encode with something that will print:
        fc = new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text".getBytes("UTF-16BE")));
        fc.close();
        // Now try reading again:
        fc = new FileInputStream("data2.txt").getChannel();
        buff.clear();
        fc.read(buff);
        buff.flip();
        System.out.println(buff.asCharBuffer());
        
        // Use a CharBuffer to write through:
        fc = new FileOutputStream("data2.txt").getChannel();
        buff = ByteBuffer.allocate(24); // More than needed
        buff.asCharBuffer().put("Some text");
        fc.write(buff);
        fc.close();
        
        // Read and display:
        fc = new FileInputStream("data2.txt").getChannel();
        buff.clear();
        fc.read(buff);
        buff.flip();
        System.out.println(buff.asCharBuffer());
    }
}
View Code
缓冲器容纳的是普通的字节,为了把它们转换成字符,我们要么在输入它们的时候对其进
行编码(这样,它们输出时才具有意义) .要么在将其从缓冲器输出时对它们进行解码。可以使
用java.nio.charset.Charset类实现这些功能,该类提供了把数据编码成多种不同类型的字符集的
工具
 
 

---------------

原文地址:https://www.cnblogs.com/tenWood/p/7471046.html