I/O系统之Java学习总结

本文深入探讨Java I/O流的基本概念,包括InputStream和OutputStream的使用,以及如何利用File类进行文件操作。同时,文章还介绍了新I/O类库的引入及其在提高性能方面的优势。此外,详细解释了内存映射文件的概念和应用,特别强调了如何通过内存映射文件高效地处理大型数据文件。

I/O系统

File类

File类不仅仅只代表存在的文件或目录。也可以用File对象来创建新的目录或尚不存在的整个目录路径。我们还可以查看文件的特性(如:大小,最后修改日期、读/写),检查某个File对象代表的是一个文件还是一个目录,并可以删除文件。

InputStream和OutputStream
流:代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。
InputStream类型
1,字节数组,ByteArrayInputSrream
2,String对象,StringBufferInputStream
3,文件,FileInputStream
4,“管道”,工作方式与实际管道相似,即,从一端输入,从另一端输出,PipedInputStream
5,一个由其他种类的流组成的序列,以便我们可以将它们收集合并到一个流内,SequenceInputStream
6,其他数据源,如Internat,

OutputStream类型
1,字节数组,ByteArrayOutputSrream
2,String对象,StringBufferOutputStream
3,文件,FileOutputStream
4,“管道”,工作方式与实际管道相似,即,从一端输入,从另一端输出,PipedOutputStream

DataInputStream和DataOutputStream
从流中读取或写入:基本数据类型

BufferedInputStreamBufferedOutputStream
它可以防止每次读取或写入都进行实际的读取或写入操作

Reader和Writer
它们提供兼容Unicode和与面向字符的I/O功能。设计Reader与Writer继承层次结构主要是为了国际化。老的I/O流继承层次结构仅支持8位字节流,并且不能很好地处理16位的Unicode字符。新类库的设计使得它的操作比旧类库更快,所以尽量使用Reader和Writer,如果不满足就使用面向节字流。

InputStreamReader和OutputStreamWriter
InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer

RandomAccessFile
它适用于大小已知的记录组成的文件,所以我们可以使用seek()将记录从一处转移到另一处,然后读取或者修改记录。文件中记录的大小不一定都相同,只要我们能够确定那些记录有多大以及它们在文件中的位置即可。在JDK1.4中,RandomAccessFile的大多数功能由nio存储映射文件所取代。

标准I/O
标准I/O意义在于:我们可以很容易的把程序串联起来,一个程序的标准输出可以成为另一个程序的标准输入。
import java.io.*;

public class Echo {
    public static void main(String[] args) throws IOException {
        BufferedReader stdin = new BufferedReader(new InputStreamReader(
                System.in));
        String s;
        while ((s = stdin.readLine()) != null && s.length() != 0) {
            System.out.println(s);
        }
    }
}

标准I/O重定向
System类提供了一些简单的静态方法调用,以允许我们对标准输入、输出和错误I/O流进行重定向
setIn(InputStream)
setOut(PrintStream)
setErr(PrintStream)
代码示例如下:
import java.io.*;

public class Redirecting {
    public static void main(String[] args) throws IOException {
        PrintStream console = System.out;
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(
                "Redirecting.java"));
        PrintStream out = new PrintStream(new FileOutputStream("test.out"));
        System.setIn(in);
        System.setOut(out);
        System.setErr(out);


        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s;
        while ((s = br.readLine()) != null){
            System.out.println(s);
        }
        out.close();
        System.setOut(console);
    }
}
I/O重定向操纵的是字节流,而不是字符流;因此我们使用的是InputStream和OutputStream,而不是Reader和Writer

新I/O

JDK1.4的java.nio.*包中引入新的Java I/O类库,其目的在于提高速度。速度的提高来自于使用的结构更接近于操作系统执行I/O的方式:通道和缓冲器。我们只上和缓冲器交互,并把缓冲器派送到通道。唯一直接与通道交互的缓冲器是ByteBuffer,它可以存储未加工的字节。

旧有I/O类库中有三个类被修改了,用以生产FileChannel。这三个类是:FileInputStream、FileOutputStream以及用于即读又写的RandomAccessFile。这个三个类的getChannel()将产生一个FileChannel,即通道:它是一种相当相当基础的东西,可以向它传送用于读写的ByteBuffer,并且可以锁定文件的某些区域用于独占访问。

Reader和Writer不能用于产生通道,但是java.noi.channels.Channels类提供了实用方法,可以在在通道中产生Reader和Writer。

简单示例如下:

import java.io.*;
import java.nio.*;
import java.nio.channels.*;

public class GetChannel {
    private static final int BSIZE = 1024;
    public static void main(String[] args) throws Exception {
        //写文件
        FileOutputStream out = new FileOutputStream("data.txt");
        FileChannel fc = out.getChannel();
        
        //使用wrap方法将已存在的字节数组“包装”到ByteBuffer中
        fc.write(ByteBuffer.wrap("Some text ".getBytes()));
        fc.close();
        out.close();
        
        //在data.txt文件的末尾添加
        RandomAccessFile randomOut = new RandomAccessFile("data.txt", "rw");
        fc = randomOut.getChannel();
        fc.position(fc.size());
        fc.write(ByteBuffer.wrap("Some more".getBytes()));
        fc.close();
        randomOut.close();
        
        //读文件
        FileInputStream in = new FileInputStream("data.txt");
        fc = in.getChannel();
        
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        
        //调用flip方法,让ByteBuffer做好让别人读取字节的准备
        buff.flip();
        while( buff.hasRemaining()){
            System.out.print((char)buff.get());
        }
        fc.close();
        in.close();
    }
}
输出:
Some text Some more

获取字符串

1,在操作ByteBuffer中过程中,读写都通过CharBuffer进行,然后调用CharBuffer的toString()输出字符串。CharBuffer通过调用ByteBuffer.asCharBuffer()获取

2,通过CharBuffer读已存在的文件而编码不正确时,可对输出字符进行编码。如:

String encoding = System.getProperty("file.encoding");
Charset.forName(encoding).decode(byteBuffer);

获取基本数据类型

字符:ByteBuffer.asCharBuffer().getChar()
short:ByteBuffer.asShortBuffer().getShort()
int:ByteBuffer.asIntBuffer().getInt()
long:ByteBuffer.asLongBuffer().getLong()
float:ByteBuffer.asFloatBuffer().getFloat()
double:ByteBuffer.asDoubleBuffer().getDouble()

内存映射文件

内存映射文件允许我们创建和修改那些因为太小而不能放入内存的文件。如下代码所例:

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class LargeMappedFiles {
    //128M
    public final static int LENGTH = 0x8FFFFFF;

    public static void main(String[] args) throws Exception{
        RandomAccessFile randomAccessFile = new RandomAccessFile("test.dat", "rw");
        
        //MappedByteBuffer是一种特殊类型的直接缓冲器
        //使用它时必须指定映射文件的初始位置和映射区域的长度  
        MappedByteBuffer out = randomAccessFile
                .getChannel().map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);
        for (int i = 0; i < LENGTH; i++){
            out.put((byte)'x');
        }
        System.out.println("Finishing writing");
        for (int i = LENGTH/2; i < LENGTH/2+6; i++){
            System.out.print((char)out.get(i));
        }
        randomAccessFile.close();
    }
}
尽管“旧”的I/O流在用nio实现后性能有所提高,但是“映射文件访问”往往可以更加显著地加快速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值