JavaSE进阶 第十二章 IO流

1.IO流概述

  • I:Input O:Output,通过IO流可以完成硬盘文件的读和写

在这里插入图片描述

  • IO流的分类:
    (1)输入输出流(按照流的方向):以内存为参照物,往内存中去,叫做输入(读);从内存中出来,叫做输出(写)
    (2)字节流(按字节方式读取数据):一次读取1个字节,这种流是万能的
    (3)字符流(按字符方式独居数据):一次读取1个字符,方便读取普通文本文件,不能读取图片、声音、视频等
  • java中主要研究如何new流对象,每个流的特点、常用方法
  • Java IO流中的四大家族InputStream(字节输入流)、OutputStream(字节输出流)、Reader(字符输入流)、Writer(字符输出流)。都是抽象类,都实现了Closeable接口,都有close()方法;输出流都实现了Flushable接口,都有flush()方法,用来将管道中剩余为输出的数据强行输出完,否则会导致丢失丢失数据
    注意:类名以Stream结尾的为字节流,以Reader\Writer结尾的为字符流
  • java.io标下需要掌握的流有16个:
    (1)文件专属:
  • FileInputStream
  • FileOutputStream
  • FileReader
  • FileWriter
    (2)转换流:(将字节流转换为字符流)
  • InputStreamReader
  • OutputStreamReader
    (3)缓冲流专属:
  • BufferedReader
  • BufferedWriter
  • BufferedInputStream
  • bufferedOutputStream
    (4)数据流专属:
  • DateInputStream
  • DateOutputStream
    (5)标准输出流
  • PrintWriter
  • PrintStream
    (6)对象专属流
  • ObjectInputStream
  • ObjectOutputStream

2.文件流

2.1FileInputStream流

2.1.1创建流、read和close方法
public class Test {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("tempfile.txt");//绝对路径或相对路径(工程的根为IDEA默认当前路径)
            byte[] bytes = new byte[4];
            //int read(byte[] b)一次读取b.length个字节,提高程序执行效率
            int readCount = 0;
            // int readDate = fis.read();这个方法的返回值为读取到的字节本身,文件末尾读不到数据返回-1
            while ((readCount = fis.read(bytes)) != -1) {   //fis.read(bytes)返回值是读取到的字节数量
                System.out.println(new String(bytes, 0, readCount));//按照读取的字节数量将数组转换为字符
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {//避免空指针异常,流为null是不必关闭
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.1.2avaiable方法

int avaiable():返回流中剩余的没有读到的字节数量

public class Test {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("tempfile.txt");
            byte[] bytes = new byte[fis.avaiable()];//获取文件字节数量,不适合太大的文件
            int readCount = fis.read(bytes);
            System.out.println(new String(bytes));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.1.3skip方法

long skip(long n):跳过几个字节不读

fis.skip(3);//跳过前3个字节不读
int next = fis.read();//读取下一个字节

2.2FileOutputStream流

public class FileOutputStreamTest {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            //fos = new FileOutputStream("myfile");文件不存在时会自动创建。这种方式会将源文件情况再写入
            fos = new FileOutputStream("myfile",true);//以追加的方式在文件末尾写入,不会清空源文件内容 
            byte[] bytes = {97, 98, 99};
            fos.write(bytes);//全部写出
            fos.write(bytes, 0, 2);//写ab

			String s = "日天家的猫";
			byte[] bs = s.getBytes();//将字符串转换为byte数组
			fos.write(bs);
			
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.3FileReader流

针对普通文本

public class FileReaderTest {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("myfile");
            //char chars = new chars[4];
            //reader.read(chars);
            //for(char c:chars){System,out.println(c);} 往char数组中读
            char[] chars = new char[4];//一次读取4个字符
            int readCound = 0;
            while ((readCound = reader.read(chars)) !=-1){
                System.out.println(new String(chars,0,readCound));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.4FileWriter流

针对普通文本

public class FileWriterTest {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            fr = new FileReader("myfile",true);
          	char[] chars = {'我','和','你'};
          	fr.write(chars);
          	fr.write(chars,0,1);
          	fr.write("心连心");
     		fr.write("\n");//换行
            fr.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3.缓冲流与转换流

3.1BufferedReader与InputStreamReader

BufferedReader:带有缓冲区的字符输入流,不需要自定义char数组或者byte数组,自带缓冲

//当一个流的构造方法中需要一个流的时候,被传进来的流叫做“节点流”,外部负责包装的流叫“包装流”或“处理流”
FileReader reader = new FileReader("myfile.java");
BufferedReader br = new BufferedReader(reader);
String s = null;
//br.readLine()方法读取一个文本行,但不带换行符
while((s = br.readLinr()) != null){System.out.println(s);}
br.close();//对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭

通过转换流将字节流装换为字符流

FileInputStream in = new FileInputStream("myfile2.java");
InputStreamReader reader = new InputStreamReader(in);
BufferedReader br = new BufferedReader(reader);
//BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("myfile2.java")));
String s = null;
while((s = br.readLinr()) != null){System.out.println(s);}
br.close();

3.2BufferedWriter与InputStreamWriter

BufferedWriter:带有缓冲的字符输出流
通过转换流将字节流装换为字符流

BufferedWriter out = new BufferedWriter(new InputStreamWriter(new FileOutputStream("myfile3.java",true)));
out.write("Hello");
out.write("\n");
out.write("World");
out.flush();
out.close();

3.3BufferedInputStream与BufferedOutputStream

需包装字节流

4.数据流

4.1DateOutputStream

数据字节输出流可以将数据连同数据类型一并写入文档(非普通文档)

DateOutputStream dos = new DateOutputStream(new FileOutputStream("date"));
int a = 24;
double b = 3.14
char c = 'a';
boolean sex = true;
dos.writeInt(a);//将数据与数据类型一同写入
dos.writeDouble(b);
dos.writeChar(c);
dos.writeBoolean(sex);
dos.flush();
dos.close();

4.2DateInputStream

数据字节输入流
DateOutputStream写的文件,必须由DateInputStream去读,并且读的时候需要记得奥写入的顺序,只有顺序一致,才能去除正确的数据

DateInputStream dis = new DateInputStream(new FileInputStream("date"));
int a = dis.readInt();
double b = dis.readDouble();
char c = dis.readChar();
boolean sex = dis.readBoolean();
dis.close();

5.标准输出流

5.1PrintStream

标准字节输出流

System.out.println("HelloWorld");
PrintStream ps = System,out;
ps.println("HelloWorld");
//标准输出流不需要手动close()关闭

改变标准输出流的输出方向,指向“Log”文件

PrintStream printStream = mew PrintStream(new FileOutputStream("Log",true));
System.setOut(printStream);
System.out.println("HelloWorld");

总结System类使用过的属性和方法

System.gc();
System.currentTimeMillis();
PrintStream ps = System.out;
System.exit(0);
System.arraycopy(...);

5.1PrintWriter

标准字符输出流,构造方法中传字符

6.对象流

6.1对象的序列化和反序列化

在这里插入图片描述

6.2序列化版本号

标志接口,没有具体代码,JVM对实现了标志接口的类可能进行特殊待遇。
参与序列化和反序列化的对象,必须实现Serializable接口。JVM就看到后,自动生成一个序列化版本号。
Java语言中区分类的机制:(1)类名(2)类名一样,通过序列化版本号区分
自动生成序列版本号的缺陷:代码确定或不可修改,修改重新编译会生成新的序列版本号,JVM会认为这是一个全新的类
结论:凡是一个类实现了Serializable接口,建议提供一个固定不变的序列化版本号(可有IDEA自动生成)

6.3序列化的实现ObjectOutputStream流

import java.io.Serializable;
public class Student implements Serializable {
    private static final long serialVersionUID = -5087935970704858855L;
    private int no;
    private String name;
    public Student() {}
    public Student(int no, String name) {this.no = no;this.name = name;}
    public int getNo() {return no;}
    public void setNo(int no) {this.no = no;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String toString() {return "Student{" +"no=" + no +", name='" + name + '\'' + '}';}
}
public class ObjectOutputStreamTest {
    public static void main(String[] args) throws Exception{
        Student s = new Student(1,"zhangsan");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
        oos.writeObject(s);
        oos.flush();
        oos.close();
    }
}

一次序列化多个对象,可以采用List集合等方式

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws  Exception{
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(1,"zhangsan"));
        studentList.add(new Student(2,"lisi"));
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students2"));
        oos.writeObject(studentList);
        oos.flush();
        oos.close();
    }
}

6.4反序列化的实现ObjectInputStream流

public class ObjectInputStreamTest01 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
        Object obj = ois.readObject();
        System.out.println(obj);
        ois.close();
    }
}

一次序列化多个对象

public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws  Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students2"));
        List<Student> studentList = (List<Student>)ois.readObject();
        for(Student student:studentList){ System.out.println(student);}
        ois.close();
    }
}

6.5 transient关键字

表示游离,不参与序列化

private transient String name;

7.File类

File对象是文件和目录路径名的抽象表示形式
File类中的常用方法

//创建File对象
File f1 = new File("D:\\file");
//判断是否存在
System.out.println(f1.exists());
//以文件形式创建,以目录形式创建
if (!f1.exists()) {
   f1.createNewFile();
}
if (!f1.exists()) {
   f1.mkdir();
}
//创建多重目录
File f2 = new File("D:/a/e/f/d");
if (!f2.exists()) {
   f2.mkdirs();
}

File f3 = new File("D:\\Steam\\steamapps");
//获得文件的父路径,以字符串或者File对象
String parentPath = f3.getPath();
File parentFile = f3.getParentFile();
System.out.println("绝对路径" + parentFile.getAbsolutePath());

//获取绝对路径
File f4 = new File("copy");
System.out.println("绝对路径" + f4.getAbsolutePath());

//获取文件名
File f5 = new File("D:\\develop\\Snipaste\\Snipaste.exe");
System.out.println("文件名" + f5.getName());

//判断是否是一个目录
System.out.println(f5.isFile());

//获取文件最后修改的时间
long haoMiao = f5.lastModified();
Date time = new Date(haoMiao);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
System.out.println(strTime);

//获取文件大小
System.out.println(f5.length());

//File中的ListFiles方法 File[] listFiles()
File f6 = new File("D:\\SoftWare\\N0vaDesktop");
//获取当前目录下的所有子文件
File[] files = f6.listFiles();
for (File file : files) {
   System.out.println(file.getAbsolutePath());
   System.out.println(file.getName());
}

8.IO流和Properties集合的联合使用

8.1配置文件

经常改变的数据,可以单独写到一个文件中,使用程序动态读取,这样不需要重新编译,服务器也不需要重启
这种文件称为属性配置文件,建议以properties结尾。Properties是专门存放属性配置文件的一个类,内容格式为

key1=value
key2=value
#在属性配置文件中#为注释
#建议key与value间用“=”方式,不建议使用“:”,最好不要有空格

8.2使用示例

//uesrinfo.properties
username=admin
password=123
FileReader reader = new FileReader("uesrinfo");
Properties pro = new Properties;
pr.load(reader);//文件中的数据流顺着管道加载到Map集合中,等号左边为key,右边为value
String usename = pr.getProperty("username");
System.out.println(username);//admin

9.示例

9.1自定义日志工具

public class Logger {
    public static void log(String msg) {
        try {
            PrintStream printStream = new PrintStream(new FileOutputStream("log.txt", true));
            System.setOut(printStream);
            Date nowTime = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd:mm:ss SSS");
            String srtTime = sdf.format(nowTime);
            System.out.println(srtTime + ":" + msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
//使用Logger.log("输出HelloWorld!");

9.2文件复制

使用FileInputStream+FileOutputStream完成文件的拷贝(一边读,一边写)
或则使用FileReader和FileWriter拷贝普通文本文件(能用记事本打开编辑)

public class CopyTest01 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("D:\\素材包\\bilidown\\Download\\AC\\1.9刺客信条:英灵殿.mp4");
            fos = new FileOutputStream("D:\\1.9刺客信条:英灵殿.mp4");
            byte[] bytes = new byte[1024*1024]; //一次拷贝1MB
            int readCount = 0;
            while((readCount=fis.read(bytes))!=-1){
                fos.write(bytes,0,readCount);
            }
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
        	//分开处理异常,不然一个流关闭出现异常会影响另一个流的关闭
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis == null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.3拷贝目录

public class CopyAll {
    public static void main(String[] args) {
        File srcFile = new File("D:\\素材包\\素材");
        File destFile = new File("C:\\");
        copyDir(srcFile, destFile);
    }

    private static void copyDir(File srcFile, File destFile) {
        if (!srcFile.isFile()) {
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream("srcFile");
                String path = destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\" + srcFile.getAbsolutePath().substring(3);
                out = new FileOutputStream("");
                byte[] bytes = new byte[1024 * 1024];
                int readCound = 0;
                while ((readCound = in.read(bytes)) != -1) {
                    out.write(bytes, 0, readCound);
                }
                out.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return;
        }
        File[] files = srcFile.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                String srcDir = file.getAbsolutePath();
                String destDir = destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\" + srcDir.substring(3);
                File newFile = new File(destDir);
                if (!newFile.exists()) {
                    newFile.mkdirs();
                }
                copyDir(file, destFile);
            }
        }
    }
}

传送门

上一章:JavaSE进阶 第十一章 集合
下一章:JavaSE进阶 第十三章 多线程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值