Java输入输出IO

1、文件对象

package file;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TestFile {
    public static void main(String[] args) {
        //创建文件对象
        //绝对路径
        File f1 = new File("d:/LOLFolder");
        System.out.println("f1的绝对路径:\t"+f1.getAbsolutePath());
        //相对路径
        File f2 = new File("LOL.exe");
        System.out.println("f2的绝对路径:\t"+f2.getAbsolutePath());
        //把f1作为父目录创建文件对象
        File f3 = new File(f1,"LOL.exe");
        System.out.println("f3的绝对路径:\t"+f3.getAbsolutePath());


        //文件常用操作1
        File f = new File("d:/LOLFolder/LOL.exe");
        System.out.println("当前文件是:\t"+f);
        //判断文件是否存在
        System.out.println("判断文件是否存在:\t"+f.exists());
        //是否是文件夹
        System.out.println("是否是文件夹:\t"+f.isDirectory());
        //是否是文件
        System.out.println("是否是文件:\t"+f.isFile());
        //文件长度
        System.out.println("获取文件长度:\t"+f.length());
        //文件的修改时间
        long time = f.lastModified();
        Date date = new Date(time);
        System.out.println("获取文件的最后修改时间:\t"+date);
        f.setLastModified(1000000000);
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd");
        long time1 = f.lastModified();
        Date date1 = new Date(time1);
        System.out.println("获取文件的设置的修改时间:\t"+sdf.format(date1));
        //文件重命名
        File f4 = new File("d:/LOLFolder/DOTA.exe");
        f.renameTo(f4);
        System.out.println("把LOL.exe改名为DOTA.exe");
        System.out.println("注意: 需要在D:\\LOLFolder确实存在一个LOL.exe,\r\n才可以看到对应的文件长度、修改时间等信息");
        System.out.println("-----------------------------------------");


        //文件常用操作2
        File file = new File("d:/LOLFolder/skin/garen.ski");
        //以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
        file.list();
        System.out.println(file.list());
        //以文件数组的方式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
        File[] files = file.listFiles();
        //以字符串形式返回所在文件夹
        System.out.println(file.getParent());
        //以文件形式返回所在文件夹
        file.getParentFile();
        //创建文件夹,如果父文件夹skin不存在,创建就无效
        file.mkdir();
        // 创建文件夹,如果父文件夹skin不存在,就会创建父文件夹
        file.mkdirs();
        //// 创建一个空文件,如果父文件夹skin不存在,就会抛出异常
        try {
            file.createNewFile();
        }catch (IOException e){
            e.printStackTrace();
        }
        // 所以创建一个空文件之前,通常都会创建父目录
        file.getParentFile().mkdirs();
        //列出所有的盘符
        System.out.println(file.listRoots());
        //删除文件
        //file.delete();
        //JVM结束的时候,删除文件,常用于临时文件的删除
        file.deleteOnExit();
    }
}

2、Stream 流

  • (1)什么是流
    当不同的介质之间有数据交互的时候,JAVA就使用流来实现。
    数据源可以是文件,还可以是数据库,网络甚至是其他的程序
    比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
    输入流: InputStream
    输出流:OutputStream


  • (2)文件输入流
    建立了一个文件输入流,这个流可以用来把数据从硬盘的文件,读取到JVM(内存)。

public class TestStream {
    public static void main(String[] args) {
        try {
            File f = new File("d:/lol.txt");
            //创建基于文件的输入流
            FileInputStream fis = new FileInputStream(f);
            // 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

3、字节流

InputStream字节输入流
OutputStream字节输出流
用于以字节的形式读取和写入数据

  • (1)以字节流的形式读取文件内容

InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取

public class TestStream {
    public static void main(String[] args) {
        try {
            //准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
            File f = new File("d:LOLFolder/lol.txt");
            //创建基于文件的输入流
            FileInputStream fis = new FileInputStream(f);
            // 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
            byte[] all = new byte[(int)f.length()];
            fis.read(all);
            for (byte b: all) {
                System.out.println(b);
            }
            fis.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

-(2)

public class TestStream {
    public static void main(String[] args) {
        try {
            //准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
            File f = new File("d:LOLFolder/lol.txt");
            //创建基于文件的输入流
            FileInputStream fis = new FileInputStream(f);
            // 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
//            byte[] all = new byte[(int)f.length()];
//            fis.read(all);
//            for (byte b: all) {
//                System.out.println(b);
//            }
            //写入文件
            byte[] data = {88,89};
            FileOutputStream fos = new FileOutputStream(f);
            fos.write(data);

            fis.close();
            fos.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

4、关闭流

所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。

  • (1)在try中关闭

在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

  • (2)在finally中关闭

这是标准的关闭流的方式

  1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
  2. 在finally关闭之前,要先判断该引用是否为空
  3. 关闭的时候,需要再一次进行try catch处理
package stream;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
 
public class TestStream {
 
    public static void main(String[] args) {
        File f = new File("d:/lol.txt");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(f);
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
                System.out.println(b);
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 在finally 里关闭流
            if (null != fis)
                try {
 
                    fis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
 
    }
}
  • (3)使用try()的方式

把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。

public class TestStream {
  
    public static void main(String[] args) {
        File f = new File("d:/lol.txt");
  
        //把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
        try (FileInputStream fis = new FileInputStream(f)) {
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
                System.out.println(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
  
    }
}

5、字符流

Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据

- (1)使用字符流读取文件
- (2)使用字符流把字符串写入到文件
public class CharStream {
    public static void main(String[] args) {
        File f = new File("d:/LOLFolder/lol.txt");
        try(FileReader fr = new FileReader(f); FileWriter fw = new FileWriter(f)){
            char[] all = new char[(int)f.length()];
            fr.read(all);
            for (char c: all) {
                System.out.println(c);
            }
            String data = "qwert12345";
            char[] cs = data.toCharArray();
            fw.write(cs);

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

6、缓存流

以介质是硬盘为例,字节流和字符流的弊端:
在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

  • (1)使用缓存流读取数据

缓存字符输入流 BufferedReader 可以一次读取一行数据

public class BufferedStream {
    public static void main(String[] args) {
        File f = new File("d:/LOLFolder/lol.txt");
        // 创建文件字符流
        // 缓存流必须建立在一个存在的流的基础上
        try(FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr)){
            while(true){
                String line = br.readLine();
                if(null == line) break;
                System.out.println(line);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
  • (2)使用缓存流写入数据

PrintWriter 缓存字符输出流, 可以一次写出一行数据

public class TestStream {  
    public static void main(String[] args) {
        // 向文件lol2.txt中写入三行语句
        File f = new File("d:/lol2.txt");    
        try (
                // 创建文件字符流
                FileWriter fw = new FileWriter(f);
                // 缓存流必须建立在一个存在的流的基础上              
                PrintWriter pw = new PrintWriter(fw);              
        ) {
            pw.println("garen kill teemo");
            pw.println("teemo revive after 1 minutes");
            pw.println("teemo try to garen, but killed again");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
    }
}
  • (3)flush

有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush

package stream;
    
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {
    public static void main(String[] args) {
        //向文件lol2.txt中写入三行语句
        File f =new File("d:/lol2.txt");
        //创建文件字符流
        //缓存流必须建立在一个存在的流的基础上
        try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
            pw.println("garen kill teemo");
            //强制把缓存中的数据写入硬盘,无论缓存是否已满
                pw.flush();           
            pw.println("teemo revive after 1 minutes");
                pw.flush();
            pw.println("teemo try to garen, but killed again");
                pw.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

7、数据流

DataInputStream 数据输入流
DataOutputStream 数据输出流、

使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写
如本例,通过DataOutputStream 向文件顺序写出 布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。

要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。

public class DataStream {
    public static void read(){
        File f = new File("d:/LOLFolder/lol.txt");
        try(FileInputStream fis = new FileInputStream(f); DataInputStream dis = new DataInputStream(fis)){
            boolean b = dis.readBoolean();
            int i = dis.readInt();
            String str = dis.readUTF();

            System.out.println("读取到布尔值:"+b);
            System.out.println("读取到整数:"+i);
            System.out.println("读取到字符串:"+str);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void write(){
        File f = new File("d:/LOLFolder/lol.txt");
        try(FileOutputStream fos = new FileOutputStream(f);DataOutputStream dos = new DataOutputStream(fos)){
            dos.writeBoolean(true);
            dos.writeInt(100);
            dos.writeUTF("hello world");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        write();
        read();

    }
}

8、对象流

对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘

一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口

  • (1)序列化一个对象

创建一个Hero对象,设置其名称为garen。
把该对象序列化到一个文件garen.lol。
然后再通过序列化把该文件转换为一个Hero对象
注:把一个对象序列化有一个前提是:这个对象的类,必须实现了Serializable接口

public class ObjectStream {
    public static void main(String[] args) {
        Hero4 h = new Hero4();
        h.name = "garen";
        h.hp = 666;
        File f = new File("d:/LOLFolder/garen.lol");
        //f.mkdirs();
        try(FileOutputStream fos = new FileOutputStream(f);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            FileInputStream fis = new FileInputStream(f);
            ObjectInputStream ois = new ObjectInputStream(fis)
        ){
            oos.writeObject(h);
            Hero4 h2 = (Hero4)ois.readObject();
            System.out.println(h2.name);
            System.out.println(h2.hp);
        }catch (IOException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}

9、System.in

System.out 是常用的在控制台输出数据的
System.in 可以从控制台输入数据

  • (1)System.in
package stream;
 
import java.io.IOException;
import java.io.InputStream;
 
public class TestStream {
 
    public static void main(String[] args) {
        // 控制台输入
        try (InputStream is = System.in;) {
            while (true) {
                // 敲入a,然后敲回车可以看到
                // 97 13 10
                // 97是a的ASCII码
                // 13 10分别对应回车换行
                int i = is.read();
                System.out.println(i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • (2)Scanner读取字符串

    使用System.in.read虽然可以读取数据,但是很不方便
    使用Scanner就可以逐行读取了
    Scanner.nextLine()

package stream;
    
import java.util.Scanner;
    
public class TestStream {
    
    public static void main(String[] args) {
         
            Scanner s = new Scanner(System.in);
             
            while(true){
                String line = s.nextLine();
                System.out.println(line);
            }
         
    }
}
  • (3)Scanner读取整数

Scanner.nextInt()

package stream;
 
import java.util.Scanner;
 
public class TestStream {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int a = s.nextInt();
        System.out.println("第一个整数:"+a);
        int b = s.nextInt();
        System.out.println("第二个整数:"+b);
    }
}

10、流 关系梳理

  1. 流分为字节流和字符流
  2. 字节流下面常用的又有数据流和对象流
  3. 字符流下面常用的又有缓存流


你可能感兴趣的:(Java输入输出IO)