IO

文件

文件就是保存数据的地方

文件流:文件在程序中是以流的形式来操作的
流:数据在数据源(文件)到程序(内存)之间经历的路径
输入流:数据从数据流到程序的路径
输出流:数据从程序流到数据源的路径。
输入和输出是以Java程序为参考点,从Java程序流出就是输出流,流入就是输入流

创建文件方法

  • new File(String path),使用文件路径创建
  • new File(File parentPath,String path),使用父文件和要创建的文件创建
  • new File(new parentPath,String childPath),使用父文件目录和子文件创建
public void create1() {
    String path = "e:\\new1.txt";
    File file = new File(path);//创建文件对象
    //将文件在磁盘中创建
    try {
        file.createNewFile();
        System.out.println("文件创建成功");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public void create2(){
    String parentPath = "e:\\";
    File parentFile = new File(parentPath);//创建父文件目录
    String fileName = "new2.txt";
    File file = new File(parentFile, fileName);
    try {
        file.createNewFile();
        System.out.println("创建文件成功");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public void create3(){
    String parentPath = "e:\\";
    String childPath = "new3.txt";
    File file = new File(parentPath, childPath);
    try {
        file.createNewFile();
        System.out.println("文件创建成功");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

只有调用createNewFile才会真正在磁盘中创建文件

获取文件相关信息

 //获取文件相关信息
String path = "e:\\new1.txt";
File file = new File(path);

System.out.println("文件名:" + file.getName());//获取文件名
System.out.println("文件绝对路径:" + file.getAbsolutePath());//获取文件绝对路径
System.out.println("文件的父级目录:" + file.getParent());//获取文件父级目录
System.out.println("文件的大小(字节):" + file.length());//获取文件的大小
System.out.println("文件是否存在: " + file.exists());//查看文件是否存在
System.out.println("文件是否是一个文件: " + file.isFile());//查看文件是否是一个文件
System.out.println("文件是否是一个目录: " + file.isDirectory());//查看文件是否是一个目录
//目录和文件的删除操作,只能删除空目录
String filepath = "e:\\new1.txt";
File file = new File(filepath);
if(file.exists()){
    //判断文件是否存在,文件就删除,不存在提示信息
    if(file.delete()){//delete删除文件
        System.out.println(filepath + "删除成功");
    }else{
        System.out.println(filepath + "删除失败");
    }
}else{
    System.out.println(filepath + "文件不存在");
}

String directory = "e:\\demo1";
File file = new File(directory);//在Java中目录也是当成文件来处理
if(file.exists()){
    //目录存在,删除目录
    if(file.delete()){//delete目录
        System.out.println(directory + "目录删除成功");
    }else{
        System.out.println(directory + "目录删除失败");
    }
}else{
    //目录不存在
    System.out.println(directory + "不存在");
}


//创建目录 e:\a\b\c
String path = "e:\\a\\b\\c";//创建多级目录
File file = new File(path);
if(file.exists()){
    //查看目录是否存在,存在不创建,提示信息
    System.out.println(path + "目录已经存在");
}else{
    if(file.mkdirs()){
        //mkdirs创建多级目录,创建一级目录只需要mkdir()
        //目录创建成功
        System.out.println(path + "创建成功");
    }else{
        System.out.println(path + "创建失败");
    }
}

IO流原理及流的分类

IO技术是非常实用的技术,用于处理数据传输,比如读写文件,网络传输等。
在Java程序中对于数据的输入和输出以“流"的形式进行
java.io包下面提供了各种流的接口和实现类,用以获取不同类型的数据并通过方法输入输出数据
输入:读取外部数据(外部不仅仅是文件,也可以是数据库,网络中的数据)到程序中
输出:将程序中的数据输出到外部

流的分类:

  • 按操作数据单位的不同分为:字节流、字符流
  • 按照数据流的流向不同分为:输入流、输出流
  • 按照流的角色不同分为:节点流、处理流/包装流
抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

字节输入流InputStream

InputStream是所有字节输入流的超类,是一个抽象类,常用子类有:

  1. FileInputStream 文件输入流
  2. BufferedInputStream 缓冲文件输入流
  3. ObjectInputStream 对象字节输入流

FileInputStream

//方式一,使用read
//从文件中读取文件,使用FileInputStream
String path = "e:\\hello.txt";
FileInputStream fileInputStream = null;//定义文件字节输入流
int read = 0;
try {
    fileInputStream  = new FileInputStream(path);
    //read,从该输入流读取一个字节的数据。数据的下一个字节,如果达到文件的末尾,返回-1 。
    while((read = fileInputStream.read()) != -1){
        System.out.print((char)read);//输出数据
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    //关闭IO资源
    try {
        fileInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//方式2使用read(byte[])
String path = "e:\\hello.txt";
FileInputStream fileInputStream = null;
byte[] buff = new byte[8];//每次读取8个字节
int length = 0;//每次实际读取数据字节数
try {
    fileInputStream = new FileInputStream(path);
    //使用read(byte[])每次读取一个指定数目的字节数,返回值是实际读取的字节数,如果返回-1表示结束
    while((length = fileInputStream.read(buff)) != -1){
        //将每次读取的字节数组转换成字符输出
        System.out.print(new String(buff,0,length));
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    //关闭IO资源
    try {
        fileInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

文件拷贝

//实现把E:\\test.jpg复制一份,E:\\test1.jpg
String srcPath = "e:\\test.jpg";
String descPath = "e:\\test1.jpg";
FileInputStream fileInputStream = null;//创建文件输入流
FileOutputStream fileOutputStream = null;//创建文件输出流
try {
    fileInputStream = new FileInputStream(srcPath);
    fileOutputStream = new FileOutputStream(descPath);
    byte[] buff = new byte[1024];//每次读取1024字节大小的数据
    int length = 0;//实际读取的大小
    while((length = fileInputStream.read(buff)) != -1){
        fileOutputStream.write(buff,0,length);
        fileOutputStream.flush();//刷新缓冲区
    }
    System.out.println("复制完成");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        fileInputStream.close();//关闭IO
        fileOutputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

字节输出流OutputStream

FileOutputStream文件字节输出流

 //使用outputStream将数据写入到文件
String path = "e:\\a.txt";//将文件写入到该地址
FileOutputStream fileOutputStream = null;
try {
    //这个方式输入默认是覆盖新内容,如果文件存在就直接写入,文件不存在,就创建文件
    fileOutputStream = new FileOutputStream(path,true);//第二次参数是用来确定是追加内容还是覆盖内容
    //写入一个字符
    //fileOutputStream.write('H');
    //写入一个字节数组
    String str = "hello";
    //            fileOutputStream.write(str.getBytes());
    //写入指定字节数组的指定大小
    //fileOutputStream.write(str.getBytes(),0,str.getBytes().length);
    fileOutputStream.write(str.getBytes(),0,3);
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        fileOutputStream.close();//关闭IO资源
    } catch (IOException e) {
        e.printStackTrace();
    }
}

字符输入流Reader

字符输入流

//使用字符输入流FileReader从文件中读取内容
String path = "e:\\story.txt";
FileReader fileReader = null;
try {
    fileReader = new FileReader(path);
    int reader = 0;
    char[] buff = new char[20];//每次读取二十个字符
    int length = 0;//记录实际长度
    //            while((reader = fileReader.read()) != -1){//每次读取一个字符
    //                System.out.print((char) reader);
    //            }
    while((length = fileReader.read(buff)) != -1){
        System.out.print(new String(buff,0,length));//每次读取一组数据,当等于-1的时候表示数据读取完成
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(fileReader != null){
        try {
            fileReader.close();//关闭IO资源
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符输出流Writer

字符输出流,在写出之前一定要关闭或者刷新缓冲区

String path = "e://story1.txt";
FileWriter fileWriter = null;
try {
    fileWriter = new FileWriter(path);
    //写出单个字符
    fileWriter.write('H');
    //写出字符数组
    fileWriter.write("hello".toCharArray());
    //写出字符串
    fileWriter.write("测试");
    fileWriter.flush();//刷新缓冲区写出数据
} catch (IOException e) {
    e.printStackTrace();
} finally {
    //关闭IO资源
    if(fileWriter != null){
        try {
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

节点流和处理流

节点流可以从一个特点的数据源读取数据,比如:FileReader、FileWriter

处理流(包装类)是连接在已经存在的流(节点流和处理流)之上,为程序提供更为强大的读取功能,比如:BufferedReader。

节点流和处理流的区别和联系

  1. 节点流是底层流/低级流,直接跟数据源相连

  2. 处理流(包装类)包装节点流,即可以消除不同节点流的实现差异,也可以提供更方便的方法来进行输入输出

  3. 处理流对节点流进行了包装,使用了修饰器设计模式,不会直接与数据源相连。

    //模拟修饰器模式
    //相当于父类Reader
    public abstract class Reader_ {
        public abstract  void read();//读内容
    }
    //相当于节点流
    public class FileReader_ extends Reader_ {
        @Override
        public void read() {
            System.out.println("读取文件内容");
        }
    }
    public class ArrayReader_ extends Reader_ {
        @Override
        public void read() {
            System.out.println("读取数组内容");
        }
    }
    //相当于处理流,内部封装父类对象属性,对原有功能进行增强
    public class BufferedReader_ extends Reader_ {
        private Reader_ reader_;
        public BufferedReader_(Reader_ reader_){
            this.reader_ = reader_;
        }
        @Override
        public void read() {
            //对读进行其它处理,增加缓存,对原有功能进行增强
            System.out.println("增加缓存");
            for(int i = 0; i < 5; i++){
                this.reader_.read();
            }
            System.out.println("读取完成,输出");
        }
    }
    
    //测试
    BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
    bufferedReader_.read();
    

    处理流的主要功能主要体现在下面两个方面:

    1. 性能的提高,主要增加缓冲的方式来提高输入输出的效率
    2. 操作的便捷,处理流可以提供跟便捷的方法来一次性输入输出大批量的数据,使用更加灵活

BufferedReader和BufferedWriter

 //使用字符输入处理流读取文件内容
String srcPath = "e:\\story.txt";
BufferedReader bufferedReader = null;
try {
    bufferedReader = new BufferedReader(new FileReader(srcPath));
    String line = null;//每次读取一行数据
    while((line = bufferedReader.readLine()) != null){
        System.out.println(line);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(bufferedReader != null){
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//使用字符输出处理流输出数据
String descPath = "e:\\new5.txt";
BufferedWriter bufferedWriter = null;
try {
    bufferedWriter = new BufferedWriter(new FileWriter(descPath,true));
    bufferedWriter.write("Hello world!");
    bufferedWriter.newLine();//新行
    bufferedWriter.write("测试");
    bufferedWriter.newLine();
    System.out.println("写出完成");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(bufferedWriter != null){
        try {
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedInputStream和BufferedOutputStream

String srcPath = "e:\\test.jpg";
String descPath = "e:\\test1.jpg";
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
    bis = new BufferedInputStream(new FileInputStream(srcPath));
    bos = new BufferedOutputStream(new FileOutputStream(descPath));
    byte[] buff = new byte[1024];
    int length = 0;
    while((length = bis.read(buff)) != -1){
        bos.write(buff,0,length);
    }
    System.out.println("拷贝完成");
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(bis != null){
        try {
            bis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    if(bos != null){
        try {
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

对象流

ObjectInputStream和ObjectOutputStream是对象流,能够进行序列化和反序列化
序列化:就是在保存数据的时候,保存数据的值和类型
反序列化:就是在恢复数据的时候,恢复数据的值和类型

需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,这个类必须实现下面两个接口之一:

  • Serializable 标记接口
  • Externalizable

ObjectOutputStream序列化功能,ObjectInputStream反序列化功能

//序列化对象,注意使用的方法不是write
String path = "e:\\data.dta";
ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream(path));
    oos.writeInt(10);//序列化 int,会自动装箱成Integer
    oos.writeBoolean(true);//序列化,会自动装箱成Boolean
    oos.writeChar('H');//序列化 ,会自动装箱成Character
    oos.writeUTF("hello");//序列化String
    oos.writeObject(new Dog("小黄",10));//序列化对象

    System.out.println("序列化完成");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(oos != null){
        try {
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//反序列化
String path = "e:\\data.dta";
ObjectInputStream ois = null;
try {
    ois = new ObjectInputStream(new FileInputStream(path));
    //进行反序列化,注意读取顺序要和写入顺序一致
    System.out.println(ois.readInt());
    System.out.println(ois.readBoolean());
    System.out.println(ois.readChar());
    System.out.println(ois.readUTF());
    Object o = ois.readObject();
    System.out.println("运行类型:" + o.getClass());
    //向下转型读取对象方法
    Dog dog = (Dog) o;
    System.out.println(dog.getName());

} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
} finally {
    if(ois != null){
        try {
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意事项:

  1. 序列化和反序列化的读写顺序要一致
  2. 要求序列化和反序列化的对象实现Serializable接口
  3. 序列化的类中建议添加SeriaVersionUID,为了提高版本兼容性 private static final long SeriaVersionUID = 1L;
  4. 序列化的时候,默认将所有的属性都序列化,但除了static和transient修饰的成员
  5. 序列化对象的时候,要求属性的类型也需要实现Serializable接口
  6. 序列化具备继承性,如果某个类已经实现了序列化,那么它的所有子类已经默认实现了序列化

标准输入输出流

System.in 标准输入 类型是:InputStream 运行类型是BufferedInputStream 默认就是键盘
System.out 标准输出 类型是PrintStream 运行类型是PrintStream 默认就是显示器

转换流

InputStreamReader:可以将一个字节输入流转换成字符输入流
OutputStreamWriter:可以将一个字节输出流转换成字符输出流

String path = "e:\\hello.txt";
BufferedReader bufferedReader = null;
try {
    bufferedReader = new BufferedReader(
        new InputStreamReader(new FileInputStream(path),"gbk"));//指定编码为GBK,解决乱码问题
    String line = bufferedReader.readLine();
    System.out.println(line);

} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(bufferedReader != null){
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//转换成字符输出流
String path = "e:\\hello1.txt";
BufferedWriter bufferedWriter = null;
try {
    bufferedWriter = new BufferedWriter(
        new OutputStreamWriter(new FileOutputStream(path),"GBK"));
    bufferedWriter.write("hello 无涯子");
    bufferedWriter.newLine();


} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(bufferedWriter != null){
        try {
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

打印流

打印流只有两种:PrintStream、PrintWriter

PrintStream out = System.out;
out.println("hello");
//写入方法是将内容写入到标准输入,就是显示器
try {
    System.setOut(new PrintStream("e:\\f1.txt"));//重置输出的地方
    System.out.println("hello");
    out.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

PrintWriter printWriter = null;
String path = "e:\\f2.txt";
try {
    printWriter = new PrintWriter(new FileWriter(path));
    printWriter.println("hello ______");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    printWriter.close();//一定要关闭打印流,不然不会写入到文件中
}

Properties

使用Properties读取文件

Properties properties = new Properties();//创建Properties集合
try {
    properties.load(new FileReader("src\\mysql.properties"));//加载文件
    properties.list(System.out);//读取所有属性
    String user = properties.getProperty("user");//读取单个属性
    String ip = properties.getProperty("ip");
    System.out.println(user);
    System.out.println(ip);
} catch (IOException e) {
    e.printStackTrace();
} finally {
}

使用Properties写入数据到文件

Properties properties = new Properties();
properties.setProperty("user","无涯子");
properties.setProperty("pwd","123");
//写出到文件
try {
    //使用字符输出流将信息写出到文件
    properties.store(new FileWriter("src\\my.properties"),null);
    System.out.println("文件写出成功");
} catch (IOException e) {
    e.printStackTrace();
}

使用Properties修改文件内容,使用setProperties重新设置即可。

posted @ 2021-10-06 19:38  无涯子wyz  阅读(540)  评论(0)    收藏  举报