Java基础-IO

输入/输出

主要是总结了一下文件操作以及序列化,NIO。

1.File类

访问文件名相关的方法:

String getName()

String getPath()

File getAbsoluteFile()

String getAbsolutePath()

String getParent()

文件检测相关方法

boolean exists()

boolean canWrite()

boolean canRead()

boolean isFile()

boolean isDirectory()

获取常规文件信息

long lastModified()

long length()

文件操作相关方法

boolean createNewFile():如果File对象对应文件不存在,该方法会新建一个指定的新文件

boolean delete():删除File对象对应的文件或路径

目录操作相关方法

boolean mkdir():创建一个File对象对应的目录

String[] list():列出File对象所有子文件名和路径名

File[] listFiles(): 列出File对象所有子文件和路径

static File[] listRoots():列出系统所有根路径

例子:

public class FileTest {

    public static void main(String[] args) {

        File file = new File(".");

        System.out.println(file.getName());

        System.out.println(file.getParent()); // 相对路径的父路径

        System.out.println(file.getAbsoluteFile()); // 绝对路径

        System.out.println(file.getAbsoluteFile().getParent()); // 上一级路径

        try {

            File tmpFile = File.createTempFile("aaa",".txt",file);
            tmpFile.deleteOnExit();
            File newFile = new File(System.currentTimeMillis() + "");

            System.out.println("newFile是否存在:" + newFile.exists());

            newFile.createNewFile(); // 创建文件
            newFile.mkdir(); // 创建目录
            String[] fileList = file.list(); // 列出当前目录下所有文件和路径
            System.out.println("当前路径下所有文件和路径如下:");

            for (String fileName : fileList)
            {
                System.out.println(fileName);
            }
            File[] roots = File.listRoots();  // 列出所有磁盘根路径
            System.out.println("系统所有根路径如下");

            for (File root : roots)
            {
                System.out.println(root);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.Java的IO流

InputStream/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流

OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流

3.对象序列化

是什么:实现序列化的Java对象转换成字符序列,这些字符序列可以保存到磁盘上。

为什么:为了让对象可以脱离程序的运行而独立存在。

主要是Serializable这个接口

使用对象流实现序列化

1.创建一个ObjectOutputStream,这是一个输出流

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“Object.txt”)); 

2.调用writeObject()方法输出可序列化对象

oos.writeObject(per);

3.Person类实现Serializable接口

public class Person implements Serializable 
{ 
    ... 
} 

4.使用ObjectOutputStream将Person对象写入磁盘文件

public class WriteObject 
{ 
    public static void main(String[] args) 
    { 
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“Object.txt”))){ 
            Person per = new Person(); 
            oos.writeObject(per);  // 将per对象写入输出流 
        } 
    } 
} 

从二进制流中恢复Java对象

1.创建ObjectInputStream输入流

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“Object.txt”));

2.调用readObject()方法读取流中的对象

Person p = (Person)ois.readObject();

4.NIO

由于流输入/输出一次只能处理一个字节,为了解决效率不高的问题,从JDK1.4开始加入了一些列改进输入/输出处理的新功能,这些功能简称新IO(NIO)

概述

新IO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样访问文件,大大提高了处理输入\输出的速度

相关包如下:

java.nio:包含于Buffer相关的类

java.nio.channels:包含Channel和Selector相关的类

java.nio.charset:包含字符集相关的类

java.nio.channels.spi:包含与Channel相关的服务提供者编程接口

java.nio.charset.spi:包含字符集相关的服务提供者编程接口

Channel和Buffer是其中核心。

Channel与传统的InputStream、OutputStream最大区别是它提供了一个map()方法,可以将数据映射到内存中。

Buffer本质上是一个数组,发送到Channel的对象都要先放到Buffer中,Channel读取数据也要到Buffer中读取。

Buffer中有3个重要概念

  • capacity:缓冲区的容量,创建后不可改变,不可为负值
  • limit:第一个不应该被读出或者写入的缓冲区位置索引,换句话说,这个索引后的区域都无法读写
  • position:用于指明下一个位置索引

例子:

public class BufferTest {

    public static void main(String[] args) {
        //创建Buffer
        CharBuffer buff = CharBuffer.allocate(8);

        System.out.println("capacity:" + buff.capacity());

        System.out.println("limit:" + buff.limit());

        System.out.println("position:" + buff.position());

        // 存放数据
        buff.put("a");

        buff.put("b");

        buff.put("c");

        System.out.println("放入三个元素后:position: " + buff.position() );

        // 调用flip()
        buff.flip();

        System.out.println("执行flip后,limit:" + buff.limit());

        System.out.println("执行flip后,position:" + buff.position());

        //调用clear()
        buff.clear();

        System.out.println("执行clear后,limit:" + buff.limit());

        System.out.println("执行clear后,position:" + buff.position());

        // 读取数据
        buff.get(2);

        System.out.println("执行读取数据后,position:" + buff.position());

        System.out.println("执行读取数据后,内容并没有被清除:" + buff.get(2));
    }
}

打印结果:

capacity:8
limit:8
position:0
放入三个元素后:position: 3
执行flip后,limit:3
执行flip后,position:0
执行clear后,limit:8
执行clear后,position:0
执行读取数据后,position:0
  • flip():把limit设置为position所在位置,将position设置为0,也就是做好输出数据准备
  • clear():将position设置为0,将limit设置为capacity,为再次输入数据做好准备,但是内容并没有被清空。

上面这个程序的执行过程就是

  • 加入三个元素后,position来到了3
  • 执行flip(),limit设置为position的值,也就是3,position设置为0
  • 执行clear(),position设置为0

为什么在写入数据完成后,需要调用flip()方法呢,因为这个时候limit到了position的位置,也就是说后面的无数据区域都无法访问,避免了读到null值。

5.使用Channel

Channel最常用的三类方法shi map()\read()\write(),其中map()方法用于将Channel对应的数据映射成ByteBuffer

例子:

public class FileChannelTest {
    public static void main(String[] args) {
        File f = new File("FileChannelTest.java");
        try {
            FileChannel inChannel = new FileInputStream(f).getChannel();

            FileChannel outChannel = new FileOutputStream("a.txt").getChannel();

            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,0,f.length());

            Charset charset = Charset.forName("GBK");

            outChannel.write(buffer);

            CharsetDecoder decoder = charset.newDecoder();

            CharBuffer charBuffer = decoder.decode(buffer);

            System.out.println(charBuffer);
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
    }
}

通过MappedByteBuffer将channel中的数据映射成ByteBuffer,然后写入FileChannel。

除了这种一次性把全部数据映射的方式,我们也可以采取类似传统字节流的方式

例子:

public class ReadFile {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("ReadFile.java");

        FileChannel fcin = fis.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(64);

        while (fcin.read(byteBuffer) != -1){
            byteBuffer.flip();
            Charset charset = Charset.forName("GBK");
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer cbuff = decoder.decode(byteBuffer);
            System.out.println(cbuff);
            cbuff.clear();
        }
    }
}

通过flip()和clear()进行读取的限制,防止读出null值。

发布了55 篇原创文章 · 获赞 37 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/blue_zy/article/details/80569005